一、map
内部实现机理
map内部实现了一个 红黑树(红黑树是非严格平衡二叉搜索树,而AVL是严格平衡二叉搜索树), 红黑树具有自动排序的功能,因此map内部的所有元素都是有序的,红黑树的每一个节点都代表着map的一个元素。因此,对于map进行的查找,删除,添加等一系列的操作都相当于是对红黑树进行的操作。map中的元素是按照二叉搜索树(又名二叉查找树、二叉排序树,特点就是左子树上所有节点的键值都小于根节点的键值,右子树所有节点的键值都大于根节点的键值)存储的,使用中序遍历可将键值按照从小到大遍历出来。
优缺点以及适用处
-
优点:有序性,这是map结构最大的优点,其元素的有序性在很多应用中都会简化很多的操作;红黑树,内部实现一个红黑树使得map的很多操作在O(logN)的时间复杂度下就可以实现,因此效率非常的高。
-
缺点:空间占用率高,因为map内部实现了红黑树,虽然提高了运行效率(低于unorder_map),但是因为每一个节点都需要额外保存父节点、孩子节点和红/黑性质,使得每一个节点都占用大量的空间(但占用的内存比unorder_map低)
-
适用处:对于那些数据存储有顺序要求的问题,用map会更高效一些
使用举例
vector<int> list = { 5,14,34,22,39,5 };
map<int, int> map;
for (int i = list.size() - 1; i >= 0; i--) {
map[i] = list[i]; //倒序插入
}
for (auto i = map.begin(); i != map.end(); i++) {
cout << i->first << ' ' << i->second << endl; //输出的数是有序的且有两个5
}
if (map.find(3) != map.end()) {
cout << "find key=" << map.find(3)->first << ", value=" << map.find(3)->second << endl;
}
if (map.count(5) > 0) { //m.count(n)计算下标为n的位置有无数据,有返回1,无返回0
cout << "count 5: " << map.count(5) << endl; //find()和count()的输入参数都是key值
}
map是基于RBT的,因此元素是有序存储的(默认按 键 的升序排列)。
输出结果:
二、unordered_map
内部实现机理
unordered_map内部实现了一个 哈希表(也叫散列表,通过把关键码值映射到Hash表中一个位置来访问记录,查找的时间复杂度可达到O(1),其在海量数据处理中有着广泛应用)。因此, 其元素的排列顺序是无序的。
优缺点以及适用处
- 优点: 因为内部实现了哈希表,因此其查找速度非常的快(运行效率快于map)
- 缺点: 哈希表的建立比较耗费时间(unorder_map占用的内存比map要高)
- 适用处:对于查找问题,unordered_map会更加高效一些,因此遇到查找问题,常会考虑一下用unordered_map
使用举例
vector<int> list = { 5,14,34,22,39,5 };
unordered_map<int, int> map;
for (int i = list.size()-1; i>=0; i--) {
map[i] = list[i]; //倒序插入
}
cout << map[0] << endl;
for (unordered_map<int, int>::iterator i = map.begin(); i != map.end(); i++) {
cout << i->first << ' ' << i->second << endl; //输出的数是有序的且有两个5
}
if (map.find(3) != map.end()) {
cout << "find key=" << map.find(3)->first << ", value=" << map.find(3)->second << endl;
}
if (map.count(5) > 0) { //m.count(n)计算下标为n的位置有无数据,有返回1,无返回0
cout << "find 5: " << map.count(5) << endl; //find()和count()的输入都是key值
}
unordered_map 是基于hash表的,因此元素是无序存储的( 不按键 升序排列)。
输出结果:
三、set
内部实现机理
set实现了红黑树的平衡二叉检索树的数据结构,插入元素时,它会自动调整二叉树的排列,把元素放到适当的位置,以保证每个子树根节点键值大于左子树所有节点的键值,小于右子树所有节点的键值;另外,还得保证根节点左子树的高度与右子树高度相等。在set中每个元素的值都唯一,而且系统能根据元素的值自动进行排序。平衡二叉检索树使用中序遍历算法,检索效率高于vector、deque和list等容器,另外使用中序遍历可将键值按照从小到大遍历出来。
使用举例
vector<int> list = { 5,14,34,22,39,5 };
set<int> set1;
for (int i = list.size() - 1; i >= 0; i--) {
set1.insert(list[i]); //倒序插入
}
for (auto i = set1.begin(); i != set1.end(); i++) {
cout << *i << endl; //输出的数是有序的且只有一个5
}
cout << "find 5: " << *set1.find(5) << endl;
cout <<"count 5: " << set1.count(5) << endl;
set 是基于RBT的,因此元素是顺序存储的(默认按 键值 升序排列)。
输出结果:
四、unordered_set
内部实现机理
unordered_set的内部实现了一个 哈希表,因此, 其元素的排列顺序是无序的。
使用举例
vector<int> list = { 5,14,34,22,39,5 };
unordered_set<int> set;
for (int i = list.size() - 1; i >= 0; i--) {
set.insert(list[i]); //倒序插入
}
for (unordered_set<int>::iterator i = set.begin(); i != set.end(); i++) {
cout << *i << endl; //输出的数是无序的且只有一个5
}
cout << "find 39: " << *set.find(39) << endl;
cout << "count 14:" << set.count(14) << endl;
unordered_set 是基于hash表的,因此元素是无序存储的( 不按键值 升序排列)。
五、总结
数据结构 | map | unordered_map | set | unordered_set |
---|---|---|---|---|
实现机理 | 红黑树 | hash表 | 红黑树 | hash表 |
元素格式 | key+value | key+value | key | key |
存储规律 | 键升序 | 无序 | 键升序 | 无序 |
元素重复 | 键不可,值可 | 键不可,值可 | 不可重复 | 不可重复 |
头文件 | #include< map> | #include<unordered_map> | #include< set> | #include<unordered_set> |