什麼是hashMap--抄自小灰

1、hashmap是一個用於存儲key-value鍵值對的集合,每一個鍵值對也叫做Entry。這些鍵值對分散存儲在一個數組當中,這個數組就是hashmap的主幹。

hashmap數組每一個元素的初始值都是Null。
在這裏插入圖片描述
對於hashmap,最常使用的兩個方法:get 和 put

2、put方法的原理
調用put方法的時候發生了什麼呢?比如調用hashMap.put(“apple”,0),插入一個key爲apple的元素,而上面有說到數組是hashmap的主幹,那麼也就是說需要知道新插入的元素所在的數組的下標。此時可以利用一個哈希函數來確定entry的插入位置(index)。
如:index = hash(“apple”)
假如最後計算出的index是2,那麼結果如下:
在這裏插入圖片描述
但是,由於hashmap的長度是有限的,如果僅使用上面的hash算法,當插入的entry越來越多時,還是會出現index衝突。
如下所示:
在這裏插入圖片描述
這時候該怎麼辦呢?可以利用鏈表來解決。
hashmap數組的每一個元素不止是一個entry對象,也是一個鏈表的頭節點,每一個entry對象通過next指針指向它的下一個entry節點,當新來的entry映射到衝突的數組位置時,只需要插入到對應的鏈表即可:
在這裏插入圖片描述
那意思就是實際插入的就是一個鏈表?(這裏的entry是一個鍵值對,其實就是hashmap中的單個元素)

3、get方法的原理
使用get方法根據key來查找value。首先會把輸入的key做一次hash映射,得到對應的index:
在這裏插入圖片描述
由於剛纔所說的hash衝突,同一個位置有可能匹配到多個entry,這時候就需要順着對應鏈表的頭節點,一個一個向下來查找。假設我們要查找的key是apple:
在這裏插入圖片描述
第一步:查看的是頭節點entry6,entry6的key是banana,顯然不是我們要找的結果。
第二步:我們查看的是next節點entry1,entry1的key是apple,正是我們要找的結果
之所以把entry6放在頭節點,是因爲hashmap的發明者認爲:後插入的entry被查找的可能性更大。

(也就是時候,hashmap本質上是一個數組,數組中的每一個元素就是一個鍵值對,在put的時候,是通過算法+key計算出應該保存在哪個下標裏,而由於算法計算出來的結果可能存在重複,所以如果是同一個下標的時候,就通過鏈表的方式保存。而在get的時候,同樣是通過key+算法計算出下標,然後通過下標從數組中獲取到數據,而獲取到的數據可能是一個鏈表,那麼此時就通過key來一個個進行對比,最終獲取到key所對應的value值。)

3、hashmap的初始長度
hashmap的初始長度是16,並且每次自動擴展或者手動初始化時,長度必須是2的冪。
(之所以要選擇16,就是爲了服務於從key映射到inex的hash算法)
之前說過,從key映射到hashmap數組的對應位置,會用到一個hash函數:
index = hash(“apple”)
那如何實現一個儘量均勻分佈的hash函數呢?可以通過利用key的hashcode值來做某種運算。
爲了實現高效的hash算法,hashmap的發明者採用了位運算的方式:其中length是hashmap的長度。
在這裏插入圖片描述
下面我們以值爲book的key來演算整個過程:
1、計算book的hashcode,結果爲十進制的3029737,二進制的101110001110101110 1001
2、假定hashmap長度是默認的16,計算length-1的結果爲十進制的15,二進制的1111.
3、把以上兩個結果做與運算,101110001110101110 1001 & 1111 = 1001,十進制9,所以index=9

可以說,hash算法最終得到的index結果,完全取決於key的hashcode值的最後幾位。
那長度爲什麼必須是16或者2的冪呢?因爲這樣做不但效果上等同於取模,而且還大大提高了性能,至於爲什麼採用16,可以試試長度爲10會出現什麼問題
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
如上圖所示,選用了三個hashcode,但是計算的結果都是1001,也就是說,當hashmap長度爲10的時候,有些index結果出現機率會更大,而有些index則永遠不會出現。所以這樣是不符合hash算法均勻分佈的原則。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章