序列式容器:底层为线性序列的数据数据结构,里面存储的是元素本身.比如:vector,list,deque.
关联式容器: 用来存储数据,与序列式容器不同的是,其里面存储的是
用来表示具有一一对应关系的一种结构,该结构一般只包括两个成员变量: key和value.key代表键值,value表示与value对应的信息.
template<classT1, classT2>
struct pair
{
typedef T1 first_type;
typedef T2 second_type;
T1first;
T2second;
pair(): first(T1()), second(T2()){}
pair(constT1&a, constT2&b): first(a), second(b){}
};
1: 与map/multimap不同,map/multimap存放的是真正的键值对
2: set中插入元素时,只需要插入value即可,不需要构造键值对.
3 set中的元素不可重复(因此可以去重),因为set底层是搜索二叉树,搜索二叉树的特征便是升序+去重.
4: set构造函数中的伪函数默认是less,代表的是升序,如果我们想用降序,可以采用great.
5: set不支持修改,因为搜索二叉树不支持修改.
方式一: 构造一个set容器,默认仿函数为less,功能为升序+去重.
set <int> s1{ 1,2,3,4 }; //升序+去重
方式二: 使用拷贝构造,构造与s1一样的set容器.
set<int> s2(s1);
方式三: 使用迭代器区间构造.
string str("yzhzzs");
set<char> s3(str.begin(), str.end());//构造与str内容相同,但是排列按照ASCLL码升序排列.
方式四: 构造一个降序的set容器.
set<int, greater<int>> s4{ 4,5,2,1};//降序+去重
使用代码示例:
int main()
{
set <int> s;
s.insert(1); //插入
s.insert(3);
s.insert(5);
s.insert(4);
s.insert(6);
auto itlow = s.lower_bound(1); //返回的是大于或者等于val的值.
auto itup = s.upper_bound(3); //返回的是大于val的值了.
cout << "[" << *itlow << "," << *itup << "]" << endl;
s.erase(itlow, itup); //删除.
for (auto e : s)
{
cout << e << " ";
}
cout << endl;
auto pos = s.find(3); //查找
if (pos != s.end())
{
s.erase(pos); //删除之前要先判断找没找到指定数
}
auto it = s.begin(); //正向迭代器.
while (it != s.end())
{
cout << *it++ << " ";
}
cout << endl;
auto rit = s.rbegin(); //反向迭代器
while (rit != s.rend())
{
cout << *rit++ << " ";
}
cout << endl;
s.clear(); //清空容器
cout << s.empty() << endl; //判断容器是否为空
}
1: multiset和set的底层都由红黑树实现.
2: multiset中,存储的也是
3: multiset的默认排列方式为由小到大.
4: multiset中的元素可以重复,set中的value是唯一的.
使用代码:
int main()
{
multiset<int> s;
s.insert(1);
s.insert(1);
s.insert(3);
s.insert(1);
s.insert(4);
auto pos = s.find(1); //返回的是底层搜索树中第一个值为val的位置.
s.erase(1);
for (auto e : s)
{
cout << e << " "; // 3 4;
}
}
1: map是关联式容器,它能按照特定的次序进行比较(按照key来比较),
存储的是pair
2: map通常由红黑树实现,并且map中的元素总是按照key来排布的.
3: map支持下标访问符,即在通过[key],就可以找到与key对应的value.
4: map通过键值key访问value的速度通常比unordered_map慢,但是map可以直接迭代得到一个有序序列.
方式一: 使用make_pair构造map.
map<int, double> m1{ make_pair(1,2),make_pair(2,3) };
方式二: 使用拷贝构造一个与m1相同的容器map.
map<int, double> m2(m1);
方式三: 使用迭代器区间指定区间构造.
map<int, double>m3(m2.begin(), m2.end());
方式四: 构造一个降序map.
map<int, double, greater<int>> m4{ make_pair(1, 2));
函数声明:
1: 如果x已经在map中,返回pair( x_iterator,false ),x_iterator指的是指向x的迭代器,插入失败时为false.
2: 如果x不在map中,返回pair( new_x_iterator,true),
new_x_iterator指的是指向新插入节点x的迭代器,插入成功时为true,.
总结:
不管插入成功还是失败,返回pair中的iterator都指向x;
pair<iterator,bool> insert ( const value_type& x )
map的插入即将pair插入到红黑树的节点,我们可以调用make_pair模板构造并获取pair.
make_pair:
template <lass T1,class T2)
pair<T1,T2> make_pair( T1 x, T2 y )
{
return ( pair< T1,T2>(x,y));
}
//map插入
int main()
{
map <int, string> m;
m.insert(make_pair(1, "苹果"));
m.insert(make_pair(2, "香蕉"));
m.insert(make_pair(3, "西瓜"));
for (auto& e : m)
{
cout << e.first << "," << e.second << endl;
}
}
函数声明:
在map中查找插入key为x的元素,找到返回该元素的位置的迭代器,否则返回指向最后一个元素的下一个位置的迭代器.
iterator find ( const key_type& x)
代码示例:
int main()
{
map <int, string> m;
m.insert(make_pair(1, "苹果"));
m.insert(make_pair(2, "香蕉"));
m.insert(make_pair(3, "西瓜"));
auto it = m.find(1);
cout << it->first<<":" << it->second << endl;
}
函数声明:
删除键值为x的元素,返回值为实际删除的元素个数.
size_type erase ( const key_type& x )
删除position位置上的元素,返回值为void.
void erase ( iterator position )
代码示例:
int main()
{
map <int, string> m;
m.insert(make_pair(1, "苹果"));
m.insert(make_pair(2, "香蕉"));
m.insert(make_pair(3, "西瓜"));
cout << m.erase(1) << endl; //1
auto it1 = m.find(2);
if (it1 != m.end())
{
m.erase(it1); //void
}
}
函数声明:
1: map中有这个key,返回的是value的引用.(查找,修改value)
2: map中没有这个key,插入pair(key,V()),返回的是value的引用(可读可写)
mapped_type& operator[] (const key_type& k)
注意:
V()是一个匿名对象,正式有了模板,T(),这个匿名对象能够根据实参转换为各种类型的对象,这个对象会主动调用默认构造.
map中的[]底层实现:
1: 不管插入成功或者失败,返回的pair中的iterator都指向key.所以我们可以像调用insert.
2: 获取insert调用的pair.
3:获取pair中的first(是一个指向key的iterator),进而获取key中pair的second.
V& operator[]( const K& key )
{
pair<iterator,bool > ret = insert(make_pair(key,V());
return ret.first->second;
}
使用代码:
int main()
{
map<int, string> m;
m.insert(make_pair(1, "苹果"));
m.insert(make_pair(2, "香蕉"));
m.insert(make_pair(3, "西瓜"));
m[2] = "榴莲"; //查找+修改
m[4] = "西红柿"; //插入+修改.
for (auto e : m)
{
cout << e.first << "," << e.second << " ";
}
}
map中迭代器遍历三种方法与其他STL容器遍历方式一样.
int main()
{
map<int, string> m;
m.insert(make_pair(1, "苹果"));
m.insert(make_pair(2, "香蕉"));
m.insert(make_pair(3, "西瓜"));
m[2] = "榴莲";
m[3] = "百香果";
m[4] = "西红柿";
for (auto e : m) //范围for遍历
{
cout << e.first << "," << e.second << " ";
cout << endl;
}
auto it1 = m.begin();
while (it1 != m.end()) //正向迭代器遍历
{
cout << it1->first << "," << it1->second << " ";
++it1;
}
cout << endl;
auto it2 = m.rbegin(); //反向迭代器遍历
while (it2 != m.rend())
{
cout << it2->first << "," << it2->second << " ";
++it2;
}
cout << endl;
}
multimap大多数的功能与map相同,唯一的区别就是:
map的key是唯一的,而multimap中的key是可以重复的.
对value没有要求,可以重复,也可以不重复.
使用代码:
int main()
{
multimap<int, string> m;
m.insert(make_pair(1, "苹果"));
m.insert(make_pair(1, "百香果"));
m.insert(make_pair(1, "百香果"));
m.insert(make_pair(2, "香蕉"));
m.insert(make_pair(3, "西瓜"));
for (auto e : m)
{
cout << "<" << e.first << "," << e.second << ">" << " ";
}
}
注意:
因为multimap允许键值冗余,所以当使用[key]时,编译器无法查找确定对应的value,所以在multimap中没有[]重载运算符.