擴容機制
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...