map类:
map是一种容器,内部元素由键值对组成,键与值的数据类型可以不同,键的值是唯一的(此处的值不是键值对中的值),用于自动排序数据值,排序方式是根据某种明确、严格的弱排序标准进行的,这种排序标准是由map内部的比较对象(即map::key_comp)指定的。使用时要引入#include <map>。
在键——值这个映射关系中,元素数据值是可以更改的,但键值是常量,一旦确定无法随意更改。必须先删除与旧元素关联的键值,才能为新元素插入新键值。
实现机理:map内部实现了一个红黑树(红黑树是非严格平衡二叉搜索树,而AVL是严格平衡二叉搜索树),红黑树具有自动排序的功能,因此map内部的所有元素都是有序的,红黑树的每一个节点都代表着map的一个元素。因此,对于map进行的查找,删除,添加等一系列的操作都相当于是对红黑树进行的操作。map中的元素是按照二叉搜索树(又名二叉查找树、二叉排序树,特点就是左子树上所有节点的键值都小于根节点的键值,右子树所有节点的键值都大于根节点的键值)存储的,使用中序遍历可将键值按照从小到大遍历出来。
特性:1、有序性。这是map类最大的优点,许多时候有序性可以省去很多麻烦,较为适合处理有顺序要求的问题;
2、唯一性。因为每个元素必须具有唯一的键值;
3、红黑树。红黑树的结构使得效率提高,许多操作可以在lgn时间复杂度下完成,但也正是该结构使得空间利用率较高,每个节点都要保存相应的父节点与子节点等;
unordered_map类:
unordered_map顾名思义就是无序的,是用来替代hash_map类的,也是使用键值对来存储数据,但是这个数据是无序的,允许通过键值直接访问元素(在常数时间O(1)内)。
实现机理:unordered_map内部实现了一个哈希表(也叫散列表,通过把关键码值映射到Hash表中一个位置来访问记录)。(哈希表是一个在时间和空间上做出权衡的经典例子。如果没有内存限制,那么可以直接将键作为数组的索引。那么所有的查找时间复杂度为O(1);如果没有时间限制,那么我们可以使用无序数组并进行顺序查找,这样只需要很少的内存。哈希表使用了适度的时间和空间来在这两个极端之间找到了平衡。只需要调整哈希函数算法即可在时间和空间上做出取舍。)
特点:哈希表的存在使得查找速度极快(常数时间O(1)),但是哈希表的建立较为消耗时间较为适合处理查找问题;
总结:哈希表较红黑树的空间占用率较高,但是执行效率要高于红黑树。
注意:虽然unordered_map是无序排列的,但是其遍历顺序与元素插入顺序是不同的,可以看如下代码:
1 #include <iostream> 2 #include <unordered_map> 3 #include <map> 4 #include <string> 5 using namespace std; 6 int main() 7 { 8 //注意:C++11才开始支持括号初始化 9 unordered_map<int, string> myMap={{ 5, "张大" },{ 6, "李五" }};//使用{}赋值 10 myMap[2] = "李四"; //使用[ ]进行单个插入,若已存在键值2,则赋值修改,若无则插入。 11 myMap.insert(pair<int, string>(3, "陈二"));//使用insert和pair插入 12 //遍历输出+迭代器的使用 13 auto iter = myMap.begin();//auto自动识别为迭代器类型unordered_map<int,string>::iterator 14 while (iter!= myMap.end()) 15 { 16 cout << iter->first << "," << iter->second << endl; 17 ++iter; 18 } 19 //查找元素并输出+迭代器的使用 20 auto iterator = myMap.find(2);//find()返回一个指向2的迭代器 21 if (iterator != myMap.end()) 22 cout << endl<< iterator->first << "," << iterator->second << endl; 23 system("pause"); 24 return 0; 25 }
当使用unordered_map时,输出如下:
3,陈二
2,李四
6,李五
5,张大
2,李四
当使用的是map时,输出如下:
2,李四
3,陈二
5,张大
6,李五
2,李四
具体细节也可以查看visual studio的帮助文档,对每一种方法都有很详细的代码解读。