HashMap 的資料結構

來源:互聯網
上載者:User

標籤:dex   alt   ati   轉變   變化   ret   下標越界   class   索引   

目錄

  • content
  • append
content

HashMap 的資料結構:

  • 數組 + 鏈表(Java7 之前包括 Java7)
  • 數組 + 鏈表 + 紅/黑樹狀結構(從 Java8 開始)

PS:這裡的《紅/黑樹狀結構》與鏈表都是鏈式結構。

HashMap 內部維護了一個數組,數組中存放鏈表的鏈首或紅/黑樹狀結構的樹根。

當鏈表長度超過 8 時,鏈表就轉換為紅/黑樹狀結構,利用紅/黑樹狀結構快速增刪改查的特點提高 HashMap 的效能;在紅/黑樹狀結構結點數量小於 6 時,紅/黑樹狀結構轉變為鏈表。

下面分別為上面兩種資料結構的圖示:

【定位演算法】

增加、尋找、刪除等操作都需要先定位到 table 數組的某個索引處。

定位演算法為三步:取 key 的 hashCode 值、高位元運算、模數運算得到索引位置。(代碼如下)

static final int hash(Object key) {    int h;    // h = key.hashCode() 第一步 取 hashCode 值    // h ^ (h >>> 16)  第二步 高位參與運算 Java8 最佳化了高位演算法,最佳化原理忽略    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);}// java7 中這是一個單獨的方法,java8 沒有了這個方法但是原理依舊static int indexFor(int h, int length) {    return h & (length-1); // hash(key) & (length-1)  第三步 模數}

模數運算h & (length -1)的結果最大值為 length -1,不會出現數組下標越界的情況。

為什麼要做高位元運算?

如果 hashCode 值都大於 length,而且這些 hashCode 的低位變化不大,就會出現很多衝突,舉個例子:

  • 假設數組的初始化容量為 16(10000),則 length -1 位 15(1111)。
  • 假設有幾個對象的 hashCode 分別為 1100 10010、1110 10010、11101 10010,如果不做高位元運算,直接使用它們做模數運算的結果將是一致的。

如果所有元素中多數元素屬於這種情況,將會導致元素分布不均勻,而對 hashCode 進行高位元運算能解決這個問題,使高位對低位造成影響改變低位的值,從而變相地使高位也參與運算。

append

【Q】負載因子與效能的關係

負載因子預設值為0.75,意味著當數組實際填充量佔比達到3/4時就該擴容了。

負載因子越大,擴容次數必然越少,數組的長度越小,減少了空間開銷;這就會導致 hash 碰撞越多,增加查詢成本。

預設值0.75在時間和空間成本上尋求一種折衷。

【Q】為什麼要擴容

因為隨著元素量的增大,hash 碰撞的機率越來越大,雖然使用鏈地址法能夠解決儲存問題,但是長長的鏈表會讓 HashMap 失去快速檢索的優勢,而擴容能解決這個問題。

HashMap 的資料結構

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.