面試題 HashMap擴容機制

2022-04-01 23:21:39 字數 2077 閱讀 5419

擴容機制

1.什麼時候才需要擴容

2.hashmap的擴容是什麼

進行擴容,會伴隨著一次重新hash分配,並且會遍歷hash表中所有的元素,是非常耗時的。在編寫程式中,要盡量避免resize。

hashmap在進行擴容時,使用的rehash方式非常巧妙,因為每次擴容都是翻倍,與原來計算的 (n-1)&hash的結果相比,只是多了乙個bit位,所以節點要麼就在原來的位置,要麼就被分配到"原位置+舊容量"這個位置。

怎麼理解呢?例如我們從16擴充套件為32時,具體的變化如下所示:

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

說明:5是假設計算出來的原來的索引。這樣就驗證了上述所描述的:擴容之後所以節點要麼就在原來的位置,要麼就被分配到"原位置+舊容量"這個位置。

因此,我們在擴充hashmap的時候,不需要重新計算hash,只需要看看原來的hash值新增的那個bit是1還是0就可以了,是0的話索引沒變,是1的話索引變成「原索引+oldcap(原位置+舊容量)」。可以看看下圖為16擴充為32的resize示意圖:

正是因為這樣巧妙的rehash方式,既省去了重新計算hash值的時間,而且同時,由於新增的1bit是0還是1可以認為是隨機的,在resize的過程中保證了rehash之後每個桶上的節點數一定小於等於原來桶上的節點數,保證了rehash之後不會出現更嚴重的hash衝突,均勻的把之前的衝突的節點分散到新的桶中了。

3. 原始碼resize方法的解讀

下面是**的具體實現:

final node resize() 

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

1)(newcap = oldcap << 1) < maximum_capacity 擴大到2倍之後容量要小於最大容量

2)oldcap >= default_initial_capacity 原陣列長度大於等於陣列初始化長度16

*/else if ((newcap = oldcap << 1) < maximum_capacity &&

oldcap >= default_initial_capacity)

//閾值擴大一倍

newthr = oldthr << 1; // double threshold

}//老閾值點大於0 直接賦值

else if (oldthr > 0) // 老閾值賦值給新的陣列長度

newcap = oldthr;

else

// 計算新的resize最大上限

if (newthr == 0)

//新的閥值 預設原來是12 乘以2之後變為24

threshold = newthr;

//建立新的雜湊表

@suppresswarnings()

//newcap是新的陣列長度--》32

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

table = newtab;

//判斷舊陣列是否等於空

if (oldtab != null)

// 原索引+oldcap

else

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

// 原索引放到bucket裡

if (lotail != null)

// 原索引+oldcap放到bucket裡

if (hitail != null) }}

}}return newtab;

}

面試筆記 HashMap擴容機制

擴容必須滿足兩個條件 1 存放新值的時候當前已有元素的個數必須大於等於閾值 2 存放新值的時候當前存放資料發生hash碰撞 當前key計算的hash值換算出來的陣列下標位置已經存在值 如果需要擴容,呼叫擴容的方法resize void resize int newcapacity entry new...

hashMap擴容機制

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

HashMap擴容機制

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