HashMap的擴容機制 為什麼是2冪

2021-09-19 13:51:20 字數 2442 閱讀 2100

假設length為hash表陣列的大小,方法indexfor(int hash, int length)為

indexfor(int hash, int length)
在舊陣列中同一條entry鏈上的元素,在resize過程中,通過重新計算索引位置後,有可能被放到了新陣列的不同位置上。jdk8做了一些優化,resize過程中對hash表陣列大小的修改使用的是2次冪的擴充套件(指長度擴為原來2倍),這樣有2個好處。

在hashmap的原始碼中。put方法會呼叫indexfor(int h, int length)方法,這個方法主要是根據key的hash值找到這個entry在hash表陣列中的位置,原始碼如下:

/**

* returns index for hash code h.

*/static int indexfor(int h, int length)

上述**也相當於對length求模。 注意最後return的是h&(length-1)。如果length不為2的冪,比如15。那麼length-1的2進製就會變成1110。在h為隨機數的情況下,和1110做&操作。尾數永遠為0。那麼0001、1001、1101等尾數為1的位置就永遠不可能被entry占用。這樣會造成浪費,不隨機等問題。 length-1 二進位制中為1的位數越多,那麼分布就平均。

以下圖為例,其中圖(a)表示擴容前的key1和key2兩種key確定索引位置的示例,圖(b)表示擴容後key1和key2兩種key確定索引位置的示例,n代表length。

元素在重新計算hash之後,因為n變為2倍,那麼n-1的mask範圍在高位多1bit(紅色),因此新的index就會發生這樣的變化:

resize過程中不需要像jdk1.7的實現那樣重新計算hash,只需要看看原來的hash值新增的那個bit是1還是0就好了,是0的話索引沒變,是1的話索引變成「原索引+oldcap」,可以看看下圖為16擴充為32的resize示意圖(一方面位運算更快,另一方面抗碰撞的hash函式其實挺耗時的):

原始碼如下

1 final node resize() 

12 // 沒超過最大值,就擴充為原來的2倍

13 else if ((newcap = oldcap << 1) < maximum_capacity &&

14 oldcap >= default_initial_capacity)

15 newthr = oldthr << 1; // double threshold

16 }

17 else if (oldthr > 0) // initial capacity was placed in threshold

18 newcap = oldthr;

19 else

23 // 計算新的resize上限

24 if (newthr == 0)

30 threshold = newthr;

31 @suppresswarnings()

32 node newtab = (node)new node[newcap];

33 table = newtab;

34 if (oldtab != null)

58 // 原索引+oldcap

59 else

66 } while ((e = next) != null);

67 // 原索引放到bucket裡

68 if (lotail != null)

72 // 原索引+oldcap放到bucket裡

73 if (hitail != null)

77 }

78 }

79 }

80 }

81 return newtab;

82 }

hashMap擴容機制

擴容時空間大小變化 hashmap中,雜湊桶陣列table的長度length大小必須為2的n次方 一定是合數 這是一種非常規的設計,常規的設計是把桶的大小設計為素數。相對來說素數導致衝突的概率要小於合數,具體證明可以參考 hashtable初始化桶大小為11,就是桶大小設計為素數的應用 hashta...

HashMap擴容機制

當map元素容量超過設定的閾值threshold capacity loadfactor時進行擴容,如下圖所示 原理 建立更大容量的新陣列,重新計算每個元素在新陣列中的位置進行遷移。缺點 每個元素需要重新計算hash 鍊錶中元素順序每次遷移後被倒置 原理 在擴充hashmap的時候,不需要像jdk1...

總結 HashMap的擴容機制

jdk1.7 hashmap擴容原理 原理 建立乙個容量的新陣列,重新計算每個元素在陣列中的位置並且進行遷移。缺點 1 擴容後每個元素需要重新計算hash。2 鍊錶中元素順序 每次遷移後被倒置。jdk1.8 hashmap擴容策略 想法 hashmap是先插入然後再擴容,有的時候我們可能會想如果先增...