HashMap中確定數組位置為什么要用hash進行擾動


HashMap數據存儲的過程先根據key獲得hash值,通過 (n - 1) & hash 判斷當前元素存放的位置(這里的 n 指的是數組的長度),如果當前位置存在元素的話,就判斷該元素與要存入的元素的 hash 值以及 key 是否相同,如果相同的話,直接覆蓋,不相同就通過拉鏈法解決沖突。

其中,jdk1.8中擾動函數hash的源碼:

static final int hash(Object key) {
    int h;
    // key.hashCode():返回散列值也就是hashcode
    // ^ :按位異或
    // >>>:無符號右移,忽略符號位,空位都以0補齊
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

其中看到在獲得hash值時將key的hashCode異或上其無符號右移16位,Hashmap這么做原因:

防止一些實現比較差的 hashCode() 方法,使用擾動函數之后可以減少碰撞,進一步降低hash沖突的幾率

打個比方, 當我們的數組長度n為16的時候,哈希碼(字符串“abcabcabcabcabc”的key對應的哈希碼)對(16-1)與操作,對於多個key生成的hashCode,只要哈希碼的后4位為0,不論不論高位怎么變化,最終的結果均為0。 如下圖所示:

1954974080(HashCode) 111 0100 1000 0110 1000 1001 1000 0000
2^4-1=15(length-1) 000 0000 0000 0000 0000 0000 0000 1111
&運算 000 0000 0000 0000 0000 0000 0000 0000

而加上高16位異或低16位的“擾動函數”后,結果如下:

原HashCode 1954974080 111 0100 1000 0110 1000 1001 1000 0000
(>>>16)無符號右移16位 29830 000 0000 0000 0000 0111 0100 1000 0110
^(異或)運算 1955003654 111 0100 1000 0110 1111 1101 0000 0110
2^4-1=15(length-1) 15 000 0000 0000 0000 0000 0000 0000 1111
&(與)運算 6 000 0000 0000 0000 0000 0000 0000 0110

可以看到: 擾動函數優化前:1954974080 % 16 = 1954974080 & (16 - 1) = 0 擾動函數優化后:1955003654 % 16 = 1955003654 & (16 - 1) = 6 很顯然,減少了碰撞的幾率。

 

參考:https://zhuanlan.zhihu.com/p/76735726


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM