HashMap 整理與分享

HashMap 分享

數據結構(數組、鏈表、樹)

  • 數組:採用一段連續的存儲單元來存儲數據。對於指定下標的查找,時間複雜度爲 O(1),但在數組中間以及頭部插入數據時,需要複製移動後面的元素。
  • 鏈表:一種在物理存儲單元上非連續、非順序的存儲結構,數據元素的邏輯順序是通過鏈表中的指針鏈接次序實現的。
  • 樹:由 n(n≥1)個有限結點組成的一個具有層次關係的集合,就像是一棵倒掛的樹。
  • 哈希表:根據關鍵碼值(Key value)直接進行訪問的數據結構。通過把關鍵碼值映射到表中一個位置來訪問記錄,以加快查找的速度。這個映射函數叫做哈希函數,存放記錄的數組就叫做哈希表。

Hashmap的數據結構圖

                         

 

負載因子

  • Hashmap中的loadFactor的字段,主要用來計算map擴容的閾值,如果構造參數不設置的話,它默認的容量是16,loadFactor爲0.75,所以計算查來map發生擴容的閾值爲:12個,只要達到這個閾值,map的數據組就會發生擴容,及調用resize()方法。
  • 對於一個map查詢效率最高的情況肯定是數組中每個地方都有值,且無鏈表狀態,這種理想狀態的查詢效率是最高的,但畢竟是理想狀態,首先map中數組下標的計算規則是(n-1) & hash 原因後面解釋,所以顯示情況中我們很難避免不同的key計算出相同的下標值,這就是哈希衝突,解決方案有很多,hashmap採用的是在發生衝突的時候維護一個單向鏈表將數值維護到鏈表中。
  • 至於負載因子爲什麼默認是0.75,肯定是默認情況下在容量與效率之前取的均衡數,在0.75的時候在大多數的情況下是比較優的,理想的情況上邊已經說了,多數還是達不到理想的情況的,比如容量16個,如果這16個的hash值算出來的下標全是一個值,將從數組變成鏈表結構,所以負載因子主要是用來綜合這個鏈表跟數組長度的職能。

索引計算

       數組下標的計算規則是(n-1) & hash,針對計算的結果直接對數組進行隨機訪問,這是效率高的原因,所以有效的索引計算方案,盡最大可能減少hash衝突是非常重要的,那麼問題來了,爲啥選用(n-1) & hash的計算規則呢?

       首先map的size爲2的n次方,所以說size必然是偶數,n-1必爲單數,即二進制的最低爲必然是1,與hash值做與運算的結果有單數也有雙數,反之的化得到的索引必然爲偶數,導致一半數組位置必然爲空,造成空間的浪費。

       第二hashmap重寫了hash算法,見下表,可以看到他對hash只做了無符號右移16爲的操作,也就是取 int 類型的一半,剛好可以將該二進制數對半切開,並且使用位異或運算(如果兩個數對應的位置相反,則結果爲 1,反之爲 0),這樣的話,就能避免上面的情況發生。這就是 hash() 方法的具體實現方式。簡而言之,就是儘量打亂 hashCode 真正參與運算的低 16 位

static final int hash(Object key) {
        int h;
     return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

 

Resize優化

        再談hashmap的擴容的優點;再1.7後的優化點主要是再擴容後的數組索引的在即 計算上,在1.7中擴容後是重新計算的entity的索引,1.8後的計算邏輯優化爲:在size 爲4的map擴容後size爲8;二進制爲0010變爲0100即爲像左移動一位,在擴容中只 用判斷原來的 hash 值和左移動的一位(newtable 的值)按位與操作是 0 或 1 就行, 0 的話索引不變,1 的話索引變成原索引加上擴容前數組。

元素的獲取優化

  • Hashmap查詢邏輯在上圖也可以看出來,拿到一個key後首先根據key計算出它的對應的數組的下標(這裏多說一句,爲什麼map要用string作爲它的key,因爲java中所有的string數組都保留在jvm的常量池中,即使new的對象的value值也是從常量池中獲取的,且string爲final修飾不會被修改,他的hash值是恆定不變的,所以可以做map的key),獲取node的鏈表,再去循環鏈表獲取相同key對應的value.鏈表的長度將直接影響查詢的效率;
  • 在1.8優化中,在鏈表長度達到8且存儲數量達到64以後會將鏈表維護成一個紅黑樹。
  • 紅黑樹與二叉樹的區別就是他允許局部的不平衡,所以可以減少二叉樹的左旋次數與右旋次數,效率上要優與二叉樹。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章