jdk1.8之前:陣列+鍊錶
jdk1.8之後:陣列+鍊錶+紅黑樹
陣列的時間複雜度:o(1)
鍊錶的時間複雜度:o(n)
紅黑樹時間複雜度:o(logn)
為什麼使用陣列?
陣列的的讀、寫速度快。(查詢快,增刪慢)
為什麼使用鍊錶?
為了避免資料的key產生雜湊碰撞後將原有的陣列下標對應的值直接替換。(查詢慢,增刪快)
為什麼使用紅黑樹?
為了解決鍊錶過長效能低的問題,增加查詢,插入,刪除的效率。
hashmap的put()和get()的實現:
map.put(k,v)實現原理
1.先將k、v封裝到node物件當中;
2.底層呼叫k的hashcode()方法計算出hash值;
3.(return h & (length-1))h代表hash值,length代表hashmap的容量
通過取模演算法計算出陣列的下標,如果下標的位置上沒有元素,就會把node新增到這個位置上,
如果下標的位置上有鍊錶,就會呼叫object中的equals方法將node中k和鍊錶中每個節點的k進行比較,相同會直接覆蓋,不相同會新增到鍊錶的末尾。
當單向鍊錶資料結構長度大於8時,會形成紅黑樹資料結構,增加效能。當紅黑樹上的節點數量小於6個,會重新把紅黑樹變成單向鍊錶資料結構。
map.get(k)實現原理
1.底層呼叫k的hashcode()方法計算出hash值;
2.通過hash值用取模演算法計算出陣列下標,快速定位到某個位置上,如果該位置上沒有值,直接返回null,
如果該位置上由單向鍊錶,就會呼叫object中的equals方法將node中k和鍊錶中每個節點的k進行比較,
如果equals方法返回false,則get結果為null,如果equals方法返回true,則get結果為該節點的value。
hashmap初始容量為什麼是16?
基於效率和記憶體使用上的乙個權衡值;
太大了浪費空間,太小了,頻繁擴容,影響效率。
為什麼載入因子為0.75f?
因為0.75正好是3/4,而容量又是2的冪,兩個數的乘積始終為整數
紅黑樹的平均查詢長度是log(n),長度為8,查詢長度為log(8)=3,鍊錶的平均查詢長度為n/2,當長度為8時,平均查詢長度為8/2=4,這才有轉換成樹的必要;
鍊錶長度如果是小於等於6,6/2=3,雖然速度也很快的,但是轉化為樹結構和生成樹的時間並不會太短。
還有選擇6和8的原因是:
中間有個差值7可以防止鍊錶和樹之間頻繁的轉換。假設一下,如果設計成煉表個數超過8則鍊錶轉換成樹結構,鍊錶個數小於8則樹結構轉換成鍊錶,如果乙個hashmap不停的插入、刪除元素,鍊錶個數在8左右徘徊,就會頻繁的發生樹轉鍊錶、鍊錶轉樹,效率會很低。
回顧 HashMap的底層資料結構
假設一段 hashmap map newhashmap map.put 張三 測試資料 map.put 李四 測試資料 對張三這個key,計算出hash值,對hash值進行取模處理,定位到陣列裡的乙個元素中去 張三,測試資料 李四,測試資料 如 map.put 張三 測試資料 對 張三 這個key計...
初步了解HashMap底層資料結構
本文主要講述hashmap的一些簡單原理,如果講的不好,可以說出來,讓我改正本文。說到hashmap的資料結構,就需要說到資料結構中的陣列和單鏈表結構,因為hashmap的底層就是陣列和鍊錶,不過這是jdk1.7版本的,1.8版本後加入了紅黑樹。下面先介紹一些這些資料結構。陣列儲存區間是連續的,占用...
redis set底層資料結構
redis的集合物件set的底層儲存結構特別神奇,我估計一般人想象不到,底層使用了intset和hashtable兩種資料結構儲存的,intset我們可以理解為陣列,hashtable就是普通的雜湊表 key為set的值,value為null 是不是覺得用hashtable儲存set是一件很神奇的事...