1. 程式人生 > 其它 >java的hashMap擴容新地址計算的巧妙

java的hashMap擴容新地址計算的巧妙

what:

  hashmap擴容

    1、重新建立一個新的陣列,長度為原陣列的兩倍(實際長度為2的n次冪);

    2、遍歷舊陣列的每個資料,重新計算每個元素在新陣列中的儲存位置(一次性完成);使用節點的hash值與舊陣列長度進行位與運算,如果運算結果為0,表示元素在新陣列中的位置不變;否則,則在新陣列中的位置下標=原位置+原陣列長度。

why:

  為什麼擴容時節點重 hash 只可能分佈在原索引位置或者 原索引長度+oldCap 位置呢?換句話說,擴容時使用節點的hash值跟oldCap進行位與運算,以此決定將節點分佈到原索引位置或者原索引+oldCap位置上的原理是什麼呢?

  

  假設老表的容量為16,則新表容量為16*2=32,假設節點1的hash值為 0000 0000 0000 0000 0000 1111 0000 1010,節點2的hash值為 0000 0000 0000 0000 0000 1111 0001 1010。

  那麼節點1和節點2在老表的索引位置計算如下圖:

    計算1(16個桶的真實計算),由於老表的長度限制,節點1和節點2的索引位置只取決於節點hash值的最後4位。

    計算2(32個桶的真實計算,擴容1倍後),計算2為元素在新表中的索引計算,可以看出如果兩個節點在老表的索引位置相同,則新表的索引位置只取決於節點hash值倒數第5位的值,而此位置的值剛好為老表的容量值16,此時節點在新表的索引位置只有兩種情況:原索引位置原索引+oldCap(放大1倍)

位置(在此例中即為10和10+16=26)。

    由於結果只取決於節點hash值的倒數第5位,而此位置的值剛好老表的容量值16,因此此時新表的索引位置的計算可以替換為計算3,直接使用節點的hash值與老表的容量16進行位於運算,如果結果為0則該節點在新表的索引位置為原索引位置否則該節點在新表的索引位置為 原索引+ oldCap 位置。