HashMap數據結構--java基礎面試大Boss

前言:

幾年前剛剛培訓java出來,參加的第一家面試,面試java基礎,第一個問題就是hashmap數據結構。

當時我的反應是這樣的:

啥?啥結構,什麼數?什麼構?不就是get、put?

後來經過百度,看各種帖子,也算是瞭解了一些,面試時也算是能跟面試官說說hashmap數據結構了,畢竟天天問。問道最後也能“談笑風聲”了。。。。

後來在工作之餘慢慢看了數據結構這本數,看了下數據結構的視頻(這裏強推趙海英的視頻),發現當時的我還真是圖樣圖森破、sometime naive。

 正文:

網上許多帖子也都提到:hashMap數據結構是數組+鏈表,但是並沒有說爲什麼要做成數組加鏈表,這樣做有什麼好處,hash查找到底是什麼這些都沒又提到,下面說說hash又名散列,在hashMap中的使用。

一: Map,在hashMap中存的最小單元便是Entry,裏面存放key和value。

二:重點在於java中hashMap中的hash是怎麼存儲這個數據的

1.hash函數

這些數據會存在一個數組中,hashMap的數組結構:

這個數組中,hash是如何實現這個快速查找的,比如下面的這一個數組中存入了許多

我們要通過key去取value的時候,需要便利這一整個數組,將每一個數據拿出來,去比較key,相同的話便取出來。這樣一來取出數據的時間複雜度便是O(n),也就是說一個長度爲n的數組,取出數據的最多比較次數是n次。那麼有沒有一種方法只要比較一次就能取出value的呢?hash(散列)就是實現這個事情的。

java中代碼是這樣的:

用過key,進行hash函數計算,直接取到節點。

根據key的hashCode計算出一個hash值(>>>移位符,右移一位最大值添0,正數時相當於除2,^異或運算)

注:爲了方便理解,下面方法沒截全

根據計算出來的hash值和數組長度,直接計算出存放數據的索引。這樣hash便實現了只需一次就可以取出value的方法。

以上就是java通過hash函數直接確定數據索引的過程。

注:&與運算,在這個地方(length-1)&hash,其中length在hashmap中是2的N次方,所以這個計算所算出來的值相當於hash%length。(2的N次方的二進制一定是1111...11這種數字,所以在使用&運算的時候相當於取餘)所以java中hashMap的hash函數使用的是除留取餘法。

2.hash衝突

通過hash函數可以之間計算出索引了,但是在put的時候,插入對象的key計算出的hash值的索引在數組中已經存在了數據怎麼辦,在hash查找中不可避免出現hash衝突。java中便是使用鏈表來處理hash衝突的(注:在java8中鏈表過長時會變成樹)

源碼:

以上便是爲何hashMap是數組加鏈表結構。並且如何實現快速hash查找。

3.hash擴容 

當hashMap中數據不斷增多,hash衝突也逐漸增多。數組中的鏈表也會越來越長,這時hash函數所帶來的快速查找優勢便逐漸消失,因爲在鏈表中查找便需要重頭到尾遍歷。

所以在數據到達一定數量時便會執行resize方法,重新組成hashMap

這個方法中便會重新排布hashMap。

這裏有一個重要的變量裝載因子:

 

如果它的值大的話,hashMap中的元素的hash衝突會增多鏈表會越拉越長,get效率低;值小的話hash衝突降低,但是執行resize的次數也會更加頻繁,put的效率會降低。java中默認的是0.75。

所以p3c插件也會提示

在hashMap初始化時指定大小,減少resize的情況。

以上便是java中對hashMap中的一些操作。

所以在談起hash結構時,主要可以基於三點:hash函數、hash衝突解決、裝載因子。

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