HashMap 為什麼長度總是2的整數次方

2021-10-06 11:16:22 字數 2038 閱讀 9723

開門見山,hashmap這樣做有兩點原因

提公升計算效率,更快算出元素的位置

減少雜湊碰撞,使得元素分布均勻

我們先看put方法的細節:

public v put(k key, v value)
其中hash(key)如下:

static final int hash(object key)
其中(h = key.hashcode()) ^ (h >>> 16)暫時不需要理解,會在文尾進行分析,這裡只需要知道hash()方法返回二次運算後的雜湊值即可。

接著回到putval()方法中:

可以看到,對於乙個key,拿到hash(key)後,之後要確定這個key在陣列中的位置,我們一般傾向於對陣列長度length取餘,餘數是幾,就在陣列的第幾個位置上,簡單方便。

但對於機器而言,位運算永遠比取餘運算快得多,在length為2的整數次方的情況下,hash(key)%length能被替換成高效的hash(key)&(length-1),兩者的結果是相等的

如果陣列長度是2的整數次方時,也就是乙個偶數,length-1就是乙個奇數,奇數的二進位制最後一位是1,因此不管hash(key)是多少,hash(key)&(length-1)的二進位制最後一位可能是0,也可能是1,取決於hash(key)。即如果hash(key)是奇數的話,則對映到陣列上第奇數個位置上。

如果length是乙個奇數的話,length-1就是乙個偶數,偶數的二進位制最後一位是0,則不管hash(key)是奇數還是偶數,該元素都會被對映到陣列上第偶數個位置上,奇數字置上沒有任何元素!

因此,陣列長度是乙個2的整數次方時,雜湊碰撞的概率起碼能下降一半,而且所有元素也能均勻地分布在陣列上

可能很多人都不知道這段**的作用,下面我談談自己的想法。

首先需要理解》的含義,即無符號右移,高位補0。例如:

0111 1110 0000 1111 1011 0001 0101 1010

右移16位得到

0000 0000 0000 0000 0111 1110 0000 1111

為什麼要使用這個運算呢,直接返回key的雜湊值不好嗎?

一般來說,任意乙個物件的雜湊值比較大,隨便例項化乙個物件,得到它的hash值

轉換成2進製後,得到

0011 1001 1010 0000 0101 0100 1010 0101
而hashmap的長度一般就在[1,2^16]左右,取length=16為例,那麼直接使用key的雜湊值&(length-1)後,得到

0011 1001 1010 0000 0101 0100 1010 0101

&0000 0000 0000 0000 0000 0000 0000 1111

---------------------------------------

0000 0000 0000 0000 0000 0000 0000 0101

可見,運算後的結果對雜湊值的高位無效,即如果兩個不同物件的雜湊值僅僅在高位上不一樣的話,依然會存在雜湊衝突的情況。因此,我們現在打算讓運算後的結果對雜湊值的高位以及低位都有效。

而對雜湊值再次運算後,即使用key.hashcode()^ (h >>> 16)運算後,將雜湊值的低16位異或了高16位,讓高位與低位都影響到了對之後位置的選擇上。

那為什麼使用^異或呢,使用|以及&不好嗎?

^能保證兩個數都能影響到最終的結果,而|中只要乙個為1,不管對方是多少,結果都為1,&也是同樣的道理,有0則0。

區別兩個細微物件的不同,就要深挖其細微之處。因此要在最大程度上避免雜湊衝突,就越要使用到所有已知的特徵,不能認為細微就沒用。

HashMap的長度為什麼要是2的n次方

hashmap訪問時,都需要計算當前key應該對應entry陣列哪個元素,即計算陣列下標 演算法如下 returns index for hash code h.staticintindexfor inth,intlength returnh length 1 hashmap為了訪問高效,要盡量較少...

HashMap 的長度為什麼是2的冪次方

為了能讓 hashmap 訪問高效,盡量較少碰撞,也就是要盡量把資料分配均勻。我們上面也講到了過了,hash 值的範圍值 2147483648到2147483647,前後加起來大概40億的對映空間,只要雜湊函式對映得比較均勻鬆散,一般應用是很難出現碰撞的。但問題是乙個40億長度的陣列,記憶體是放不下...

HashMap的長度為什麼要是2的N次方

先貼一段原始碼壓壓驚,the default initial capacity must be a power of two.static final int default initial capacity 1 4 aka 16見上面的原始碼中的注釋,must be a power of two ...