1. 程式人生 > >STL—map、hash_map、unordered_map

STL—map、hash_map、unordered_map

hashmap 取余 擴容 函數 取值 key值 uno 運算 一個

1.基本定義


  map底層是用紅黑樹實現的,查找時間復雜度是O(log(n));

  hash_map底層是用hash表存儲的,查詢時間復雜度是O(1);

2.hash_map


  hash_map基於哈希表,因此數據插入和查找的時間復雜度幾乎是常數時間,而代價是消耗比較多的內存。底層實現上,使用一個下標範圍比較大的數組來存儲元素,形成很多的桶,利用hash函數對key進行映射到不同區域進行保存。

    插入操作:使用key通過hash函數得到hash值 -> 得到桶號(hash值對桶數求模) -> 存放key和value在桶內

    取值過程:使用key通過hash函數得到hash值 -> 得到桶號(hash值對桶數求模) -> 比較桶內元素與key是否相等 -> 取出相等紀錄的value

  因此hash_map和用戶相關的是:hash函數和比較函數,這兩個參數剛好是我們在使用hash_map時需要指定的參數。如果每個桶內部只有一個元素,那麽查找的時候只有一次比較,因此查詢時間復雜度是O(1)。

  在容器中不包含key值時,insert函數只要立刻插入新節點。但是當容器中元素增多,每個桶中的元素會增加,為了保證效率, hash_map會自動申請更大的內存,以生成更多的桶,因此在insert以後,以前的iterator有可能是不可用的。

  【1】hash_map桶的擴容機制

    擴容時需要滿足兩個條件:存放新值的時候當前hash_map所有元素的個數大於等於閾值;存放新值的時候當前存放數據發生hash碰撞。

    STL會默認指定初始桶大小為16,負載因子是0.75,因此閾值就是16*0.75 = 12,所以當新插入元素時,當前的元素個數超過12,並且發生了沖突,就會擴容hash桶。擴容的大小是給之前的數組翻倍。

    在hashmap數組擴容之後,最消耗性能的點就出現了:原數組中的數據必須重新計算其在新數組中的位置,並放進去,這就是resize。 所以如果已經預知hashmap中元素的個數,那麽預設元素的個數能夠有效的提高hashmap的性能,例如最多有1000個元素,則創建時:new HashMap(2048)(1024是不夠的,要考慮負載因子:1024*0.75 = 768)。

    另外桶的大小為2的冪次方時,hash_map的效率最高。這是因為:正常的取index方法為hash%length,但是由於位運算比取余快,所以代碼中實現為index = hash & (length - 1),所以只有length大小為2的次冪時:hash % length == hash & (length - 1)。

3.


  總體來說,hash_map 查找速度會比map快,屬於常數級別;而map的查找速度是log(n)級別。並不一定常數就比log(n)小, 因為hash函數計算也需要耗時,如果在元素達到一定數量級時同時要考慮效率,此時應該使用hash_map。如果對內存使用特別嚴格,需要程序盡可能少消耗內存,那麽應該是用map,因為hash_map占用內存較多。

  

STL—map、hash_map、unordered_map