java Hashmap原理分析

2021-09-02 16:47:35 字數 2898 閱讀 3472

[size=medium][color=red][b]1. hashmap的資料結構[/b][/color][/size]

資料結構中有陣列和鍊錶來實現對資料的儲存,但這兩者基本上是兩個極端。

[b]陣列[/b]

陣列儲存區間是連續的,占用記憶體嚴重,故空間複雜的很大。但陣列的二分查詢時間複雜度小,為o(1);陣列的特點是:定址容易,插入和刪除困難;

[b]鍊錶[/b]

鍊錶儲存區間離散,占用記憶體比較寬鬆,故空間複雜度很小,但時間複雜度很大,達o(n)。鍊錶的特點是:定址困難,插入和刪除容易。

[color=red][b]雜湊表[/b][/color]

那麼我們能不能綜合兩者的特性,做出一種定址容易,插入刪除也容易的資料結構?答案是肯定的,這就是我們要提起的雜湊表。[b]雜湊表((hash table)既滿足了資料的查詢方便,同時不占用太多的內容空間,使用也十分方便。[/b]

雜湊表有多種不同的實現方法,我接下來解釋的是最常用的一種方法—— 拉鍊法,我們可以理解為「[color=red][b]鍊錶的陣列[/b][/color]」 ,如圖:

[img]

[img]

從上圖我們可以發現雜湊表是由陣列+鍊錶組成的,乙個長度為16的陣列中,每個元素儲存的是乙個鍊錶的頭結點。那麼這些元素是按照什麼樣的規則儲存到陣列中呢。一般情況是通過hash(key)%len獲得,也就是元素的key的雜湊值對陣列長度取模得到。比如上述雜湊表中,12%16=12,28%16=12,108%16=12,140%16=12。所以12、28、108以及140都儲存在陣列下標為12的位置。

[color=darkblue][b]hashmap其實也是乙個線性的陣列實現的,所以可以理解為其儲存資料的容器就是乙個線性陣列。[/b][/color]這可能讓我們很不解,乙個線性的陣列怎麼實現按鍵值對來訪問資料呢?這裡hashmap有做一些處理。

首先hashmap裡面實現[color=red][b]乙個靜態內部類entry,其重要的屬性有 key , value, next[/b][/color],從屬性key,value我們就能很明顯的看出來entry就是hashmap鍵值對實現的乙個基礎bean,我們上面說到hashmap的基礎就是乙個線性陣列,這個陣列就是entry,map裡面的內容都儲存在entry裡面。

[size=medium][color=red][b]2. hashmap的訪問實現[/b][/color][/size]

// 儲存時:

int hash = key.hashcode(); // 這個hashcode方法這裡不詳述,只要理解每個key的hash是乙個固定的int值

int index = hash % entry.length;

entry[index] = value;

// 取值時:

int hash = key.hashcode();

int index = hash % entry.length;

return entry[index];

[size=medium][color=blue][b]1)put[/b][/color][/size]

疑問:如果兩個key通過hash%entry.length得到的index相同,[b]會不會有覆蓋的危險?[/b]

這裡hashmap裡面用到鏈式資料結構的乙個概念。上面我們提到過entry類裡面有乙個next屬性,作用是指向下乙個entry。打個比方, 第乙個鍵值對a進來,通過計算其key的hash得到的index=0,記做:entry[0] = a。一會後又進來乙個鍵值對b,通過計算其index也等於0,現在怎麼辦?hashmap會這樣做:b.next = a,entry[0] = b,如果又進來c,index也等於0,那麼c.next = b,entry[0] = c;這樣我們發現index=0的地方其實訪問了a,b,c三個鍵值對,他們通過next這個屬性鏈結在一起。所以疑問不用擔心。也就是說陣列中儲存的是最後插入的元素。到這裡為止,hashmap的大致實現,我們應該已經清楚了。

public v put(k key, v value)

}modcount++;

addentry(hash, key, value, i);

return null;

}void addentry(int hash, k key, v value, int bucketindex)

當然hashmap裡面也包含一些優化方面的實現,這裡也說一下。比如:entry的長度一定後,隨著map裡面資料的越來越長,這樣同乙個index的鏈就會很長,會不會影響效能?hashmap裡面設定乙個因子,隨著map的size越來越大,entry會以一定的規則加長長度。

[color=red][b]2)get[/b][/color]

public v get(object key)

return null;

}

[color=red][b]3)確定陣列index:hashcode % table.length取模[/b][/color]

hashmap訪問時,都需要計算當前key應該對應entry陣列哪個元素,即計算陣列下標;演算法如下:

/**

* returns index for hash code h.

*/static int indexfor(int h, int length)

按位取並,作用上相當於取模mod或者取餘%。

[size=medium][color=red][b]這意味著陣列下標相同,並不表示hashcode相同。[/b][/color][/size]

[size=medium][color=red][b]先找陣列再找鍊錶[/b][/color][/size]

**:[url]

java HashMap 實現原理

hashmap 我們不陌生,他是允許存放null 物件的,他的結構其實就是乙個陣列,不過稍微複雜一點 把這個圖畫出來,起始就很好理解了,首先我們來看一下他的構造方法 constructs a new empty instance.suppresswarnings unchecked public h...

Java HashMap實現原理

連續記憶體位址 資料元素 ox0001 jack ox0010 rose ox0011 petter ox0100 john 特點 1 隨機訪問表中元素。2 插入和刪除操作需要移動元素。記憶體位址 資料元素 下個位址 ox0001 jack ox0111 ox1010 rose ox0100 ox0...

Java HashMap原始碼分析

hashset和hashmap是相同的實現 主要分析hashmap hashmap實現了map介面,允許放入null元素,與hashtable的主要區別是沒有實現執行緒安全,與treemap的主要區別是不能保證元素的順序,因此,不同時間迭代會得到不同的位置,hashmap是用衝突鍊錶法解決衝突 根據...