Java集合:HashMap

划水的魚dm 發表於 2021-09-19
Java HashMap

Hashmap是一個儲存key-value的對映表。

優點:

  • 索引資料快,查詢一個資料對的時間複雜度是O(1)
  • 增加、刪除一個資料的時間複雜度是O(1)
  • key不能重複,可以儲存一個null值

儲存:

  • 通過key的hashcode值儲存在指定陣列下標中
  • 用連結串列儲存hashcode值一樣,都是key不一樣的資料,連結串列長度大於8時轉換為紅黑樹(為了提高查詢效率)

HashMap的內部結構

Hashmap封裝了一個Node陣列進行儲存key-value的鍵值對,常用的get和put等都是對這個Node陣列進行操作。

Node有四個屬性:key、value、hash、next

  • hash:32位的整數,通過key的hashcode計算出來,hash&(陣列長度-1) = 元素在陣列的下標
  • next:指向Node節點的指標,不同的key計算出來的hash值可能是一樣的,如果要儲存的下標位置已經有值了,用連結串列將元素連起來

初始化HashMap:一開始HashMap內部是一個空的Node陣列,插入資料後才會被建立

HashMap的常用操作

HashMap一開始的Node陣列是空的,在第一次put元素後會預設建立一個長度為n = 16的陣列

put一個key-value元素進入map中

計算key的hashcode值算出hash,得出index=hash&(長度-1),將元素存在陣列[index]的位置。

有兩種情況:

  • index這個位置已經有key了,比如當陣列的長度是16時,33&(16-1) = 1. ,  1 & (16 - 1) = 1 ; key值不同,但是index一樣。

    這裡就用到了Node的next屬性,讓陣列index下標所在的(最後一個)元素的next指向插入的元素,

  • 可以直接將元素存入陣列中

通過key從map中get一個元素

計算key的hashcode值算出hash,得出index=hash&(長度-1)

有兩種情況:

  • 如果陣列[index]的值為null,就說明不存在這個元素
  • 不為null,還得比較key值,通過遍歷連結串列(如果有的話),一個個比較key值,返回key相同的元素,或null

HashMap的優化操作

  • 陣列長度n永遠是2的冪:hash&(n-1)是元素在陣列的下標,(2的冪-1)的二進位制會是一連串的1,然後與hash值進行與運算
    • 與運算之後的結果永遠不會超過陣列的界限
    • 充分的利用了hash值二進位制
  • 負載因子:hashmap設定了一個0.75的閾值,也就是陣列中的元素數量大於陣列長度的0.75時,進行陣列擴容,擴充套件成原來的兩倍
    • 當陣列長度不夠時,會出現很多的hash衝突,就是連結串列很長,檢索效率慢,擴容後通過hash&(n-1)會讓很長的連結串列散開
  • 連結串列轉換成紅黑樹:連結串列長度大於8,但是陣列元素數量沒達到閾值,會選擇將連結串列轉換為紅黑樹,提高查詢效率
    • 要求陣列長度已經大於64,避免陣列擴容和連結串列轉紅黑樹的衝突
  • hash值的計算:hash值的前16位與key的hashcode一樣,後16位由hashcode的前16位與後16位異或運算得到
    • 充分利用hashcode的值,增加隨機性,減少hash衝突