HashMap 的工作原理及代碼實現,什么時候用到紅黑樹


HashMap工作原理及什么時候用到的紅黑樹:

在jdk 1.7中,HashMap采用位桶+鏈表實現,即使用鏈表處理沖突,同一hash值的鏈表都存儲在一個鏈表里。但是當位於一個桶中的元素較多,即hash值相等的元素較多時,通過key值依次查找的效率較低

在jdk 1.8中,HashMap采用位桶+鏈表+紅黑樹實現,當鏈表長度超過閾值(8)時,將鏈表轉換為紅黑樹,這樣大大減少了查找時間。

原理:數組中的每一個元素所在的位置相當於一個位桶,添加元素的時候,首先計算元素key的hash值,確定插入數組中的位置(也就是哪個桶中),如果存在相同的hash值,則放在同一個桶中(元素位置)形成鏈表,當鏈表長度超過閾值(8)時,將鏈表轉換為紅黑樹;

HashMap的內部結構:

HashMap 底層是基於數組和鏈表實現的,如圖所示,其中兩個重要的參數:容量和負載因子;容量的默認大小是 16,負載因子是 0.75,當 HashMap 的 size > 16*0.75 時就會發生擴容(容量和負載因子都可以自由調整)

 

內部包含了一個Node類型的數組 table(Entry<K,V>[] table為jdk 1.7中)。
transient Node<K,V>[] table;

 

 

Node存儲着鍵值對。它包含了四個字段,從 next 字段我們可以看出Node是一個鏈表。即數組中的每個位置被當成一個桶,一個桶存放一個鏈表。HashMap 使用拉鏈法來解決沖突,同一個鏈表中存放哈希值相同的Node;

拉鏈法的工作原理(解決hash沖突):

新建一個 HashMap,默認大小為 16;

  • 插入 <K1,V1> 鍵值對,先計算 K1 的 hashCode 為 115,使用除留余數法得到所在的桶下標 115%16=3。
  • 插入 <K2,V2> 鍵值對,先計算 K2 的 hashCode 為 118,使用除留余數法得到所在的桶下標 118%16=6。
  • 插入 <K3,V3> 鍵值對,先計算 K3 的 hashCode 為 118,使用除留余數法得到所在的桶下標 118%16=6,插在 <K2,V2> 前面。
  • 應該注意到鏈表的插入是以頭插法方式進行的,例如上面的 <K3,V3> 不是插在 <K2,V2> 后面,而是插入在鏈表頭部;

查找需要分成兩步進行:

  • 計算鍵值對所在的桶;
  • 在鏈表上順序查找,時間復雜度顯然和鏈表的長度成正比;

HashMap 允許插入鍵為 null 的鍵值對。但是因為無法調用 null 的 hashCode() 方法,也就無法確定該鍵值對的桶下標,只能通過強制指定一個桶下標來存放。HashMap 使用第 0 個桶存放鍵為 null 的鍵值對。

注意:

  • 在並發環境下使用 HashMap 容易出現死循環。

  • 並發場景發生擴容,調用 resize() 方法里的 rehash() 時,容易出現環形鏈表。這樣當獲取一個不存在的 key 時,計算出的 index 正好是環形鏈表的下標時就會出現死循環。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM