1.关联式容器
什么是关联式容器呢?
关联式容器时用来存储数据的,与序列式容器(vector、list、deque)不同的是,其存储的是<key,value>结构的键值对,在数据检索时比序列式容器效率更高。
2.键值对
刚才提到的键值对又是什么?
用来表示具有一一对应关系的一种结构,该结构中一般只有两个成员变量key,value,key代表键值,value表示与key对应的信息。
STL键值对的定义:
template <class T1, class T2>
struct pair
{
typedef T1 first_type;
typedef T2 second_type;
T1 first;
T2 second;
pair(): first(T1()), second(T2())
{}
pair(const T1& a, const T2& b): first(a), second(b)
{}
};
3.树形结构关联式容器
STL中实现了两种不同结构的管理式容器:树形结构和哈希结构。树形结构的关联式容器有四种:map、set、multimap、multiset。他们都是用平衡搜索二叉树(红黑树)作为底层。我们之后再来了解底层,先来看一下他们四个。
3.1set
介绍:
- set是按照一定次序储存元素的容器
- 在set中,value必须是唯一的。set中的元素不能在容器中修改(const),但是可以从容器中插入或者删除他们。
- 在内部,set中的元素是按照其内部比较对象)所指示的特定严格弱排序准则进行排序。
- set在底层是用二叉搜索树(红黑树)实现的。
注意:
- 与map/multimap不同,map/multimap中存储的是真正的键值对,set中只放 value,但在底层实际存放的是由构成的键值对。
- set中插入元素时,只需要插入value即可,不需要构造键值对。
- set中的元素不可以重复(因此可以使用set进行去重)。
- 使用set的迭代器遍历set的元素,可以得到有序序列
- set中的元素默认按照小于来比较
- set中的元素不允许修
set功能的举例![](https://i-blog.csdnimg.cn/blog_migrate/970e0c27523836a343c000fd655c0fa0.png)
可以看到构造set时可以应用[first,last) 区间中的元素来构建。
3.2 map
介绍:
- map时关联容器,他按照特定的次序(key)储存键值key和值value组成的元素
- map中,键值key通常用于排序和标识元素,而值value中储存的键值key关联的内容。键值key和值value的类型可能不同,并且在map的内部,key与value通过成员类型 value_type绑定在一起,为其取别名称为pair。
- 在内部,map中的元素是按照key进行比较排序的
- map支持下标访问,即在[]中放入key,就可以找到对应的value (这也是map的灵魂所在)
注意:
-
map中的元素是键值对
-
map中的key是唯一的,且不能修改
-
默认按照小于的方式对key进行比较
-
map中的元素如果用迭代器去遍历,可以得到一个有序的序列
-
支持[]操作符,operator[]中实际进行插入查找。
map的功能举例及用法
void TestMap()
{
map<string, string> m;
// 向map中插入元素的方式:
// 将键值对<"peach","桃子">插入map中,用pair直接来构造键值对
m.insert(pair<string, string>("peach", "桃子"));
// 将键值对<"peach","桃子">插入map中,用make_pair函数来构造键值对
m.insert(make_pair("banan", "香蕉"));
// 借用operator[]向map中插入元素
/*
operator[]的原理是:
用<key, T()>构造一个键值对,然后调用insert()函数将该键值对插入到map中
如果key已经存在,插入失败,insert函数返回该key所在位置的迭代器
如果key不存在,插入成功,insert函数返回新插入元素所在位置的迭代器
operator[]函数最后将insert返回值键值对中的value返回
*/
// 将<"apple", "">插入map中,插入成功,返回value的引用,将“苹果”赋值给该引用结果,
m["apple"] = "苹果";
// key不存在时抛异常
//m.at("waterme") = "水蜜桃";
cout << m.size() << endl;
// 用迭代器去遍历map中的元素,可以得到一个按照key排序的序列
for (auto& e : m)
cout << e.first << "--->" << e.second << endl;
cout << endl;
// map中的键值对key一定是唯一的,如果key存在将插入失败
auto ret = m.insert(make_pair("peach", "桃色"));
if (ret.second)
cout << "<peach, 桃色>不在map中, 已经插入" << endl;
else
cout << "键值为peach的元素已经存在:" << ret.first->first << "--->"
<< ret.first->second << " 插入失败" << endl;
// 删除key为"apple"的元素
m.erase("apple");
if (1 == m.count("apple"))
cout << "apple还在" << endl;
else
cout << "apple被吃了" << endl;
}
3.3 multiset
介绍:
- multiset中再底层中存储的是的键值对
- mtltiset的插入接口中只需要插入即可,不需要去重
- 与set的区别是,multiset中的元素可以重复,set是中value是唯一的
- 使用迭代器对multiset中的元素进行遍历,可以得到有序的序列
- multiset中的元素不能修改
- multiset的作用:可以对元素进行排序
简单看一下与set不同的使用
#include <set>
void TestSet()
{
int array[] = { 2, 1, 3, 9, 6, 0, 5, 8, 4, 7 };
// 注意:multiset在底层实际存储的是<int, int>的键值对
multiset<int> s(array, array + sizeof(array)/sizeof(array[0]));
for (auto& e : s)
cout << e << " ";
cout << endl;
return 0;
}
3.4multimap
介绍:
multimap和map的唯一不同就是:map中的key是唯一的,而multimap中key是可以重复的。
注意:
- multimap中的key是可以重复的。
- multimap中的元素默认将key按照小于来比较
- multimap中没有重载operator[]操作
ok map和set先介绍这么多,底层的avl树和红黑树我们下回分解~