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的幫助文檔,對每一種方法都有很詳細的代碼解讀。