1、关联式容器:关联式容器相对于序列式容器来说,序列式容器存储的是元素本身,而关联式容器存储的是<key, valuse>这样的键值对,因此相对于序列式容器来说检索速度就更快。
2、树形关联式容器:本文看的是树形结构的关联容器,主要有map, multimap, set, multiset;下面为四种容器的对比以及常见操作的使用:
容器名称 | 底层结构 | 查询元素效率 | 特点 |
map | 二叉搜索树(红黑树) | O(logN) | 1、map<key, value> 2、支持下标访问,调用insert函数 3、key值不允许重复,按照key值自动排序,默认为升序 4、可用来解决TopK问题 |
multimap | 二叉搜索树(红黑树) | O(logN) | 与map相比:1、不支持下标访问 2、key值可以重复 |
set | 二叉搜索树(红黑树) | O(logN) | 1、set<key> 不区分key与valuse 2、元素唯一 3、不支持下标访问 4、不允许修改元素 5、可用来进行元素去重排序 |
multiset | 二叉搜索树(红黑树) | O(logN) | 与set相比元素可重复,可用来进行元素排序 |
// map容器:key唯一 ,默认按照key进行排序,且为升序
// 支持下标访问,通过key值找到唯一对应的value值
// multimap 与map用法类似,只是不支持下标访问,因为其key值不唯一
#include <map>
void testMap() {
map<string, int> m;
// map的三种插入操作
m.insert(pair<string, int>("孙悟空", 20));
m.insert(make_pair("猪八戒", 30));
// operator[]底层调用insert函数,
// 如果key值存在则插入失败,返回key值所在位置的迭代器
// 如果key值不存在,使用下表运算符可以插入元素
// 返回新插入元素所在位置的迭代器
m["沙僧"] = 40;
cout << "根据key值访问" <<endl;
cout << m["孙悟空"] << endl;
cout << "检测insert函数的返回值" << endl;
auto ret = m.insert(make_pair("唐僧", 50));
if(ret.second) {
cout << "唐僧不存在,已插入" << endl;
} else {
cout << "唐僧已存在,插入失败" << ret.first->first << "-" << ret.first->second <<endl;
}
cout << "元素个数:" << m.size() << endl;
cout << "遍历:" << endl;
for(auto e : m) {
cout << e.first << "-" << e.second << endl;
}
cout << endl;
cout << "根据key值删除指定元素" << endl;
m.erase("唐僧");
cout << "元素个数:" << m.size() << endl;
}
// set容器: 键值对中只有key值没有实际的valuse值
// 去重排序,不允许修改元素,可以插入删除
// multiset与set用法基本相同,不同点在于
// set可以在去重同时排序
// multiset只能排序,不能去重
#include <set>
void testSet() {
int arr[] = {0,2,4,1,3,7,5,8,9,4,2,3,7,5,6};
set<int> s;
for(auto& e : arr) {
s.insert(e);
}
cout << s.size() << endl;
for(auto e : s) {
cout << e << endl;
}
cout << endl;
auto ret = s.insert(1);
if(ret.second) {
cout << "1不存在,插入成功" << endl;
} else {
cout << "1已存在,插入失败" << *ret.first << endl;
}
s.erase(1);
cout << s.size() << endl;
}
3、底层结构:四种容器的底层都为二叉搜索树/二叉排序树
二叉搜索树特点:
①若左子树不为空,左子树的所有节点都比根节点的值小
②若右子树不为空,右子树所有节点都比根节点的值大
③左右子树均为二叉搜索树
二叉搜索树查找:
①将要查找的元素与根节点进行对比
②若相等则返回true
③若比根节点值大,则去右子树进行查找
④否则去左子树进行查找
二叉搜索树的插入:
①若树为空,则直接插入
②树不为空,则按照二叉搜索树的性质进行插入
二叉搜索树的删除:
①如果要删除的结点无子节点直接删除;只有左节点或只有右节点,删除该节点之后将该节点的根结点与该节点的左、右节点连接起来
②若要删除的结点左右节点都存在,则去该节点的右子树的中序遍历中找第一个结点来填充到要删除的节点的位置,然后再删除要删除的节点