[Java復習] 面試突擊 - 集合


JDK 1.8 中hash算法和尋找算法是如何優化?

// JDK 1.8以后的HashMap里面的一段源碼

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

高低16位參與運算:

比如有一個key的hash值

原值:        1111 1111 1111 1111     1111 1010 0111 1100

右移16位:0000 0000 0000 0000  1111 1111 1111 1111

異或運算: 1111 1111 1111 1111     0000 0101 1000 0011 -> 轉換成int值表示hash值

尋址算法優化:

(n - 1) & hash  -> 算出數組里的一個位置下標

取模運算性能差一些,為了優化數組尋址過程,數組長度2的n次方,hash & (n – 1)效果跟hash對n取模效果一樣,與運算性能更高。

核心在於低16的與運算

hash算法的優化:對每個hash值,在他的低16位中,讓高低16位進行了異或,讓他的低16位同時保持了高低16位的特征,盡量避免一些hash值后續出現沖突,大家可能會進入數組的同一個位置。

 

HashMap如何解決hash碰撞問題?

hash沖突問題,鏈表+紅黑樹,O(n)和O(logn)

map.put和map.get -> hash算法優化(避免hash沖突),尋址性能優化

假設你的鏈表很長,可能會導致遍歷鏈表,性能會比較差,O(n)

優化,如果鏈表的長度達到了一定的長度之后,其實會把鏈表轉換為紅黑樹,遍歷一顆紅黑樹找一個元素,此時O(logn),性能會比鏈表高一些。

 

說說HashMap是如何進行擴容的?

2的N次方擴容。16,32,64。。。

rehash:

如果數組的長度擴容之后 = 32,重新對每個hash值進行尋址,也就是用每個hash值跟新數組的length - 1進行與操作。

n-1          0000 0000 0000 0000  0000 0000 0001 1111

hash1      1111 1111 1111 1111     0000 1111 0000 0101

&結果      0000 0000 0000 0000  0000 0000 0000 0101 = 5(index = 5的位置)

 

n-1          0000 0000 0000 0000 0000 0000 0001 1111

hash2     1111 1111 1111 1111     0000 1111 0001 0101

&結果    0000 0000 0000 0000   0000 0000 0001 0101 = 21(index = 21的位置)

 

判斷二進制結果中是否多出一個bit的1,如果沒多,那么就是原來的index,如果多了出來,那么就是index + oldCap,通過這個方式,就避免了rehash的時候,用每個hash對新數組.length取模,取模性能不高,位運算的性能比較高。

 

參考資料:

互聯網Java工程師面試突擊(第三季)-- 中華石杉


免責聲明!

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



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