1、hashmap的儲存結構
陣列+鍊錶+紅黑樹(jdk1.8)
如下圖所示:
2、hashmap的特點,如何實現
我們知道hashmap是一種可以快速儲存很快速查詢的鍵值容器,那麼jdk是如何實現hashmap的快速儲存和快速查詢呢?
我們先從陣列和鍊錶以及二叉查詢樹這三種資料結構說起
1)陣列
陣列結構是連續的記憶體位址,陣列的部分元素被連續存放在cpu快取中,利用二分查詢法,陣列的時間複雜度位低到o(1),可見陣列的查詢效率是非常高的。但是由於陣列的記憶體占用嚴重,空間複雜度很高,所以陣列的增刪操作效率將非常低下。
2) 鍊錶
鍊錶記憶體位址比較分散,空間複雜度較低,在插入和刪除上效率較高。但是記憶體位址過於分散,導致查詢效率大大降低。
3) 二叉查詢樹
二叉樹在查詢效率上和排序後陣列的二分查詢效率完全相同,從根節點開始,到下面分支節點左邊的永遠比父節點的要小,右邊比父節點大。
如下圖所示:
圖中共12個元素,如果順序查詢,可能最多需要查詢12次才能查到需要的元素,但是通過查詢樹後,我們查詢43這個元素只需要判斷4次就可以。
由此我們可以看出二叉查詢樹在查詢效率上和排序後的陣列二分查詢效率是相當的。但是由於二叉樹的元素過於分散,導致空間複雜度過大,在插入和刪除上回非常低效。為了解決這個問題,jdk使用了紅黑樹這種資料結構,而紅黑樹在時間複雜度上可以做到 o(log n) 的高效率。
綜合以上三種資料結構的特點,那麼hashmap到底是如何保證高效儲存和高效查詢的呢?沒錯,hashmap有效的利用了各個資料結構的長處。
實現快速儲存
快速儲存是鍊錶和紅黑樹以及,無移動新增陣列元素的優勢。
hashmap中陣列的索引是通過hashcode的無符號右移16位後異或然後取餘獲得,公式如下
index = [(hashcode)^ (hashcode>>>16) ] / 陣列的長度
通過這樣的計算可以保證陣列索引的分散。但是分散並不代表不會出現相同的index,也就是索引衝突(hash衝突)。在遇到索引衝突的時候,hashmap會在該索引的位置生成乙個單向鍊錶,將元素放置到next。 但是我們知道鍊錶這種資料結構在儲存方面高效,但是在查詢上回非常低效。所以hashmap在鍊錶元素大於8個的時候,會自動將鍊錶轉成紅黑樹,以達到查詢高效,插入也高效的目的。當然,在紅黑樹中元素個數小於一定數量,也會變回原來的鍊錶結構,jdk設定這個數量為6個。
這樣不管是在外圍 "陣列" 上還是在 "鍊錶" 上 以及 變成 "紅黑樹" 這種資料結構,hashmap都能做到快速儲存。
hashmap對陣列的擴容觸發條件是陣列元素達到長度的0.75 (75%),使用這樣的觸發條件jdk是從時間和空間角度上思考的,為了這個條件更加容易被觸發,也要考慮到暫用過多記憶體浪費資源,75%位非常理想化的觸發條件。
實現快速查詢
hashmap的外圍陣列這點毋庸置疑,查詢效率絕對不會存在問題。索引衝突變成鍊錶,元素數量僅僅只有8個的鍊錶,查詢效率不需要考慮。 大於8個元素後變成的紅黑樹,二叉查詢樹的查詢效率和陣列相當,這點也不需要質疑。綜合考慮在查詢方面hashmap,也做到了快速查詢的特性。
HashMap底層原理
1.hashmap概述 hashmap是基於雜湊表的map介面的非同步實現。此實現提供所有可選的對映操作,並允許使用null值和null鍵。此類不保證對映的順序,特別是它不保證該順序恆久不變。2.hashmap的資料結構 注意,迭代器的快速失敗行為不能得到保證,一般來說,存在非同步的併發修改時,不可...
HashMap底層原理
hashmap實現map介面,非執行緒安全的,區別於concurrenthashmap。允許使用null值和null鍵,不保證對映的順序.底層資料結構是乙個 陣列 鍊錶 紅黑樹 put 根據key計算得到key.hash h k.hashcode h 16 根據key.hash計算得到桶陣列的索引i...
HashMap底層原理
預設負載因子 static final float default load factor 0.75f 無參構造 public hashmap 有參構造 public hashmap int initialcapacity public hashmap int initialcapacity,flo...