Java集合:HashMap
- 2021 年 9 月 19 日
- 筆記
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衝突