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衝突