之前粗略看了一下list和map,今咱來聊一下set。
主要看以下幾個:
(1)hashset
(2)collections.synchronizedset
(3)linkedhashset
(4)copyonwritearrayset
(5)treeset
一、hashset
hashset是日常搬磚中最常用的,如果有了解過hashmap的實現,那麼hashset你也就理解了。
(1)hashset底層就是用hashmap實現的,也就是非執行緒安全。
private transient hashmapmap;
//構造乙個初始容量16,載入因子是0.75的hashmap
public hashset()
既然是用hashmap實現的,那麼問題來了,set存的只是乙個物件,而hashmap存的是鍵值對,怎麼用hashmap作為set的底層呢?
(2)新增元素
private static final object present = new object();
public boolean add(e e)
可以看到,hashset只使用了hashmap的key,而值present是乙個物件常量。這也是為什麼set裡面的元素都是唯一的。
返回是map.put(e, present)==null表示式,hashmap在新增值的時候如果已有則返回舊值,反之,返回null,所以這也是set判斷重複新增值的時候是否新增成功。
二、collections.synchronizedset
這是用collections工具類直接生成的,可以知道其是執行緒安全的
(1)底層使用synchronizedset實現
public static setsynchronizedset(sets)
而synchronizedset又是繼承自synchronizedcollection,其方法都是使用synchronized關鍵字實現執行緒安全的。
static class synchronizedsetextends synchronizedcollectionimplements set
synchronizedset(sets, object mutex)
public boolean equals(object o)
}public int hashcode() }}
三、linkedhashsetlinkedhashset是hashset的子類,但底層跟hashset有些區別。
(1)預設構造
public linkedhashset()
點進super,可以看到底層是初始容量為16,載入因子為0.75的雙向鍊錶
hashset(int initialcapacity, float loadfactor, boolean dummy)
四、copyonwritearrayset這個類名字比較牛掰,寫時複製set,也是juc包中多執行緒安全的類。
(1)底層結構
public copyonwritearrayset()
其底層是用copyonwritearraylist實現的。
關於copyonwritearraylist是如何實現的,可具體檢視list原始碼解析。
五、treeset
treeset的底層是treemap,而treemap底層資料結構是紅黑樹。
public treeset()
在map原始碼解析那一篇並沒有說treemap,那麼今天剛好看一下紅黑樹。
treemap的節點結構如下:
class entryimplements map.entry
紅黑樹其實就是平衡二叉樹,其還有五點定義:
(1)節點是黑色或者紅色。
(2)根節點是黑色。
(3)每個紅色節點的兩個子節點都是黑色節點。
(4)每個葉子的節點都是黑色的空節點(null)。
(5)從任意節點到其每個葉子節點的所有路徑都包含相同數量的黑色節點。
下圖就是乙個紅黑樹
當插入和刪除節點的時候,就會破壞紅黑樹的平衡,此時需要對節點進行變色和旋轉以達到平衡。
比如我插入乙個節點21 。
可以看到,此時破壞了規則3(每個紅色節點的兩個子節點都是黑色節點),
此時我們可以進行變色(此時只關注根節點的右子樹)
(1)將22變成黑色
此時變色之後破壞了規則5(從任意節點到其每個葉子節點的所有路徑都包含相同數量的黑色節點。),比如17->15只有1個黑色節點,17->21有兩個黑色節點。
(2)將25變成紅色
此時違反了規則3(每個紅色節點的兩個子節點都是黑色節點),需要把17和27都變成黑色
(3)將17和27變成黑色
可以看到,此時根節點的右子樹已經符合其他規則了,但不是平衡樹,接下來看下整棵樹
可以看到,整棵樹是違反規則5的(從任意節點到其每個葉子節點的所有路徑都包含相同數量的黑色節點。),比如13->6有2個黑節點,而13->21有3個,所以這是需要進行左旋轉。
(4)左旋轉,(以13為點,將右子樹向上撥,將17作為根節點,將17原有的左子樹15節點作為13節點的右子節點)
此時左右子樹違反了規則5的(從任意節點到其每個葉子節點的所有路徑都包含相同數量的黑色節點。),比如17->7有3個黑色節點,但17->21才2個黑色節點,此時將13進行變色
(5)13變色,13的子節點相應進行變色。
但此時對左子樹來說還是不符合規則5(從任意節點到其每個葉子節點的所有路徑都包含相同數量的黑色節點。),比如13->1有1個黑色節點,13->6有兩個,此時需要右旋轉
(6)右旋轉(以8為軸點,將13往下撥,變為8的右節點,8原有的右節點11變成13的左節點)
右旋轉之後左子樹是不符合規則5的(從任意節點到其每個葉子節點的所有路徑都包含相同數量的黑色節點。),所以進行將8進行變色:
變色之後的樹是符合紅黑樹的規則了。
以上就是紅黑樹增加節點的時候,結構重新恢復平衡的步驟。(插入節點預設是紅色的)。
紅黑樹在增刪的時候,需要先進行節點變色,如果變色已經解決不了了,就相應進行旋轉,旋轉之後如果不成功,再重複上述步驟。
上述就是set原始碼解析了,順帶也重新了解了乙個紅黑樹。
我是liusy,乙個喜歡健身的程式設計師。
提前祝大傢伙中秋國慶快樂!!!
Set原始碼解析(紅黑樹)
之前粗略看了一下list和map,今咱來聊一下set。主要看以下幾個 1 hashset 2 collections.synchronizedset 3 linkedhashset 4 copyonwritearrayset 5 treeset 一 hashset hashset是日常搬磚中最常用的...
TreeMap 紅黑樹 原始碼解析
紅黑樹是一種平衡二叉搜尋樹。它可以在o log n 的時間內完成查詢,插入和刪除。二叉搜尋樹 左邊的節點都小於父節點,右邊的節點都大於父節點。平衡二叉樹 任意左右兩個子樹的葉子節點的高度相差不超過1。關於二叉樹的分類可以看筆者的這篇文章 一句話弄懂常見二叉樹型別 分成這兩個概念來看,紅黑樹就非常好理...
紅黑樹原始碼及錯誤解析
學校 大學 版本 紅黑樹初始版本 include stdio.h include malloc.h define min 99999999 不要加等號 define max 99999999 struct node long key char color struct node p struct n...