unordered_map 與 map 的對比(轉)
unordered_map和map類似,都是存儲的key-value的值,可以通過key快速索引到value。不同的是unordered_map不會根據key的大小進行排序,
存儲時是根據key的hash值判斷元素是否相同,即unordered_map內部元素是無序的,而map中的元素是按照二叉搜索樹存儲,進行中序遍歷會得到有序遍歷。
所以使用時map的key需要定義operator<。而unordered_map需要定義hash_value函數並且重載operator==。但是很多系統內置的數據類型都自帶這些,
那麽如果是自定義類型,那麽就需要自己重載operator<或者hash_value()了。
1.結論
結論:如果需要內部元素自動排序,使用map,不需要排序使用unordered_map
運行效率方面:unordered_map最高,而map效率較低但 提供了穩定效率和有序的序列。
占用內存方面:map內存占用略低,unordered_map內存占用略高,而且是線性成比例的。
需要無序容器,快速查找刪除,不擔心略高的內存時用unordered_map;有序容器穩定查找刪除效率,內存很在意時候用map。
2.原理
map的內部實現是二叉平衡樹(紅黑樹);hash_map內部是一個hash_table一般是由一個大vector,vector元素節點可掛接鏈表來解決沖突,來實現.
- 得到key
- 通過hash函數得到hash值
- 得到桶號(一般都為hash值對桶數求模)
- 存放key和value在桶內。
- 得到key
- 通過hash函數得到hash值
- 得到桶號(一般都為hash值對桶數求模)
- 比較桶的內部元素是否與key相等,若都不相等,則沒有找到。
- 取出相等的記錄的value。
3.性能特點
非頻繁的查詢用map比較穩定;頻繁的查詢用hash_map效率會高一些,c++11中的unordered_map查詢效率會更高一些但是內存占用比hash_map稍微大點。unordered_map 就是 boost 裏面的 hash_map 實現。其實,stl::map對於與java中的TreeMap,而boost::unordered_map對應於java中的HashMap。
python中的map就是hashmap實現的,所以查詢效率會比C++的map查詢快。(java,python官方版的虛擬機都是用C語言實現的,所以內部的思想和方法都是通用的。)
若考慮有序,查詢速度穩定,容器元素量少於1000,非頻繁查詢那麽考慮使用map。
若非常高頻查詢(100個元素以上,unordered_map都會比map快),內部元素可非有序,數據大超過1k甚至幾十萬上百萬時候就要考慮使用unordered_map(元素上千萬上億時4GB的內存就要擔心內存不足了,需要數據庫存儲過程挪動到磁盤中)。
hash_map相比unordered_map就是千萬級別以上內存占用少15MB,上億時候內存占用少300MB,百萬以下都是unordered_map占用內存少,
且unordered_map插入刪除相比hash_map都快一倍,查找效率相比hash_map差不多,或者只快了一點約1/50到1/100。
綜合非有序或者要求穩定用map,都應該使用unordered_map,set類型也是類似的。
unordered_map 查找效率快五倍,插入更快,節省一定內存。如果沒有必要排序的話,盡量使用 hash_map(unordered_map 就是 boost 裏面的 hash_map 實現)。
4.使用案例
map:
1 #include<string> 2 #include<iostream> 3 #include<map> 4 5 using namespace std; 6 7 struct person 8 { 9 string name; 10 int age; 11 12 person(string name, int age) 13 { 14 this->name = name; 15 this->age = age; 16 } 17 18 bool operator < (const person& p) const 19 { 20 return this->age < p.age; 21 } 22 }; 23 24 map<person,int> m; 25 int main() 26 { 27 person p1("Tom1",20); 28 person p2("Tom2",22); 29 person p3("Tom3",22); 30 person p4("Tom4",23); 31 person p5("Tom5",24); 32 m.insert(make_pair(p3, 100)); 33 m.insert(make_pair(p4, 100)); 34 m.insert(make_pair(p5, 100)); 35 m.insert(make_pair(p1, 100)); 36 m.insert(make_pair(p2, 100)); 37 38 for(map<person, int>::iterator iter = m.begin(); iter != m.end(); iter++) 39 { 40 cout<<iter->first.name<<"\t"<<iter->first.age<<endl; 41 } 42 43 return 0; 44 }
輸出為:(根據age進行了排序的結果)
Tom1 20
Tom3 22
Tom4 23
Tom5 24
因為Tom2和Tom3的age相同,由我們定義的operator<只是比較的age,所以Tom3覆蓋了Tom2,結果中沒有Tom2。
如果運算符<的重載是如下
1 bool operator < (const person &p)const{ 2 return this->name < p.name; 3 }
輸出結果: 按照 那麽進行的排序,如果有那麽相同則原來的那麽會被覆蓋
Tom1 20
Tom2 22
Tom3 22
Tom4 23
Tom5 24
參考:http://www.cnblogs.com/NeilZhang/p/5724996.html
http://blog.csdn.net/blues1021/article/details/45054159
unordered_map 與 map 的對比(轉)