一.為什么要有紅黑樹這種數據結構?
我們知道ALV樹是一種嚴格按照定義來實現的平衡二叉查找樹,所以它查找的效率非常穩定,為O(log n),由於其嚴格按照左右子樹高度差不大於1的規則,插入和刪除操作中需要大量且復雜的操作來保持ALV樹的平衡(左旋和右旋),因此ALV樹適用於大量查詢,少量插入和刪除的場景中
那么假設現在假設有這樣一種場景:大量查詢,大量插入和刪除,現在使用ALV樹就不太合適了,因為ALV樹大量的插入和刪除會非常耗時間,那么我們是否可以降低ALV樹對平衡性的要求從而達到快速的插入和刪除呢?
答案肯定是有的,紅黑樹這種數據結構就應運而生了(因為ALV樹是高度平衡的,所以查找起來肯定比紅黑樹快,但是紅黑樹在插入和刪除方面的性能就遠遠不是ALV樹所能比的了)
二.紅黑樹的簡介
紅黑樹是一種特殊的二叉查找樹,每個結點都要儲存位表示結點的顏色,或紅或黑
紅黑樹的特性:
1)每個結點或紅或黑
2)根結點是黑色
3)空葉子結點是黑色
4)如果一個結點是紅色,那么它的子節點是黑色
5)從任意一個結點出發到空的葉子結點經過的黑結點個數相同(比如下圖中80到任意一個空葉子結點經過的黑結點都是3)
示意圖:(紅黑樹首先是一顆搜索樹,所以左子樹點小於根結點,右子樹大於根節點,等於根結點的按照自己的需要放左邊和右邊都是可以的)(紅黑樹不僅是一顆搜索樹還是一顆非嚴格的平衡樹)
圖1
現在有個問題:紅黑樹是怎么通過上面5條性質保證任意結點到空的葉子結點的所有路徑中,沒有一條路徑會大於其他路徑的兩倍的呢?(換句話說就是它是如何確保任何一個結點的左右子樹的高度差不會超過二者中較低那個的一倍的呢?)
先結合紅黑樹的5個性質分析一下紅黑樹的一些操作,我們可能就明白了!
三.紅黑樹的基本操作之旋轉
紅黑樹的基本操作是添加和刪除,在對紅黑樹進行添加和刪除之后,都會用到旋轉方法,為什么呢?道理很簡單,因為添加或者刪除紅黑樹中的結點之后,紅黑樹就發生了變化,可能不滿足上面的5條性質了,這個時候就需要通過旋轉操作來保證它依舊是一棵紅黑樹,旋轉分為左旋和右旋
(旋轉操作僅僅只是用來調節結點的位置的,就是為了滿足紅黑樹的性質5)
1.左旋
圖2

左旋是將X的右子樹繞X逆時針旋轉,使得X的右子樹成為X的父親,同時修改相關結點的引用,旋轉之后,要求二叉查找樹的屬性依然滿足
2.右旋
圖3

右旋是將X的左子樹繞X順時針旋轉,使得X的左子樹成為X的父親,同時注意修改相關結點的引用,旋轉之后要求仍然滿足搜索樹的屬性
四.紅黑樹的基本操作之添加元素
添加操作宏觀過程:首先將紅黑樹當作一顆查找樹一樣將結點插入,然后將結點着為紅色,最后通過旋轉和重新着色的方法使之重新成為紅黑樹
將新加入的結點塗成紅色的原因:
1)不違背紅黑樹的性質5:從任意一個結點出發到空葉子結點,經過的黑色結點個數相同
2)按照紅黑樹的性質4我們知道紅黑樹中黑結點的個數至少是紅結點個數的兩倍,所以新增結點的父親結點是黑結點的概率比較大,如果新增結點的父節點為黑色,那么此時不需要再去進行任何調整操作,因此效率很高,所以新結點應該塗成紅色
少違背一條性質,意味着我們后續的旋轉和重新着色操作會簡單很多
現在我們來看看新增一個紅色的結點會違背紅黑樹的5條性質中的哪些?
1)每個結點或紅或黑
2)根結點是黑色
3)空葉子結點是黑色
4)如果一個結點是紅色,那么它的子節點是黑色
5)從任意一個結點出發到空的葉子結點經過的黑結點個數相同
1.顯然沒有違背
2.根據查找樹的特定,插入操作不好改變根結點,所以也沒有違背
3.插入的肯定不是空葉子結點,所以也沒有違背
4.有可能違背!!!
5.插入結點塗成紅色就是為了不違背第5條性質
現在我們來分析一下新增的結點(紅色)插入之后可能面臨的幾種情況,以及他們的處理措施
1.插入的結點為根結點
將新插入的紅色結點變成黑色結點,滿足根結點為黑色結點的要求!
2.父親結點為黑色結點
這個時候不需要進行任何調整操作,此時的樹仍然是一顆標准的紅黑樹
3.父親結點為紅色結點的情況下,叔叔結點為紅色結點(不用考慮左右)
解決方案:將叔叔和父親結點改為黑色,爺爺結點改為紅色,未完
然后又將爺爺結點當作插入結點看待,一直進行上面的操作,直到當前結點為根結點,然后將根結點變成黑色
原圖:
圖4
插入一個125的結點:
圖5
現在125結點和130結點都是紅色的,顯然違背了規則4,所以將新插入結點的父親130結點和插入結點的叔叔結點150變成黑色,並將新插入結點的爺爺結點140變成紅色,圖如下:
圖6
然后又將140結點當作新插入結點處理(因為140結點和新插入結點面臨的情況都是一樣的:和父親結點都是紅色),也就是做如下處理:將140結點的父親結點120和140的叔叔結點60變成黑色結點,將140結點的爺爺結點變成紅色,因為遍歷到了根結點,要滿足根結點是黑色的性質要求,所以又將140的爺爺結點也就是根結點變成黑色,圖如下:
圖7
到這里,為新插入結點125所做的某些結點重新着色的操作就完成了,現在該樹是標准的紅黑樹了!
4.新插入的結點的父親結點為紅色,其叔叔結點為黑色,
1)父親結點為爺爺結點的左孩子,新插入結點為父節點的左孩子(左左情況)
2)父親結點為爺爺結點的右孩子,新插入結點為父親結點的右孩子(右右情況)
上述兩種情況都是同一個處理辦法
比如下圖,新插入結點為25,其父親結點30為紅色,其叔叔結點為空黑色葉子結點,且新插入結點和其父節點都是左孩子:
圖8
我們將其父親結點和爺爺結點顏色互換,然后針對爺爺結點進行一次左旋,圖如下:
圖9
現在這顆樹完全滿足紅黑樹的5個性質了(最好自己對照5個性質看一下)
現在又一個問題,我們為什么要進行旋轉?
假設我們只將新增結點的父親結點和其爺爺結點的顏色互換了,圖如下:
圖10
我們發現上述兩條到葉子結點的路徑經過的黑色結點數量不一樣!!!,所以它不滿足紅黑樹的第5條性質,所以這就是我們旋轉的意義所在!!!(因為無論你這么旋轉都沒有改變結點顏色,改變的是結點的位置,而這位置改變剛好能使得樹滿足紅黑樹的第5條性質!)
5.新插入的結點的父親結點是紅色,其叔叔結點是黑色
1)插入結點是右結點,父節點是左結點
2)插入結點是左結點,父親結點是右結點
上述兩種情況都是同一個處理辦法
比如下圖,新插入結點是126,其父結點125為紅色,其叔叔結點為空的黑色結點,而且插入結點是右結點,父結點是左結點
圖11
我們將父親結點125看作當前結點進行左旋,旋轉結果如下:
圖12
現在我們的當前結點是125,現在125的處境和上面的情況4是一樣的(父節點為紅,叔叔結點為黑,插入結點為左結點,父親結點也為左孩子)現在我們繼續按照情況4的處理辦法處理上述情況(措施和情況4一樣,父親結點和爺爺結點互換顏色,然后針對爺爺結點進行左旋),處理后情況如下:
圖13
現在樹就是一顆標准的紅黑樹了!
我們現在總結一下插入結點面臨的幾種情況以及采取的措施:
1.樹為空,插入的結點為根結點
直接將插入的結點變成黑色
2.父親結點為黑色結點
不需要任何操作
3.父親結點為紅色結點的情況下:
3.1 叔叔結點也為紅色結點
將叔叔和父親結點改為黑色,爺爺結點改為紅色,未完,然后又將爺爺結點當作插入結點看待,一直進行上
面的操作,直到當前結點為根結點,然后將根結點變成黑色
3.2 叔叔結點為黑色結點的情況下:
3.2.1 (父親結點為左孩子,插入結點也為左孩子)||(父親結點為右孩子,插入結點也為右孩子)
將父親結點和爺爺結點的顏色互換,然后針對爺爺結點進行一次左旋
3.2.2 (父親結點為左孩子,插入結點為右孩子)||(父親結點為右孩子,插入結點為左孩子)
針對父結點進行左旋,此時左旋后的情況必定是3.2.1的情況,然后按照3.2.1的情況處理
現在我們來討論一下,為什么插入的情況只有上面這些:
1.爺爺結點為紅色結點的情況下,父親結點只能為黑色(紅黑樹的性質4),處理操作:上面情況2
2.爺爺結點為黑色的情況下,父親結點和叔叔結點:可以為紅色,也可以為黑色
2.1 父親結點為黑,叔叔結點為黑:處理操作:上面情況2
2.2 父親結點為黑,叔叔結點為紅:處理操作:上面情況2
2.3 父親結點為紅,叔叔結點為紅:處理操作:上面情況3.1
(上面3種情況都是不用考慮左右的)
2.4 父親結點為紅,叔叔結點為黑:
2.4.1 父親結點為左孩子,叔叔結點為左孩子:處理操作:上面情況3.2.1
2.4.2 父親結點為右孩子,叔叔結點為右孩子:處理操作:上面情況3.2.1
2.4.3 父親結點為左孩子,插入結點為右孩子:處理操作:上面情況3.2.2
2.4.4 父親結點為右孩子,插入結點為左孩子:處理操作:上面情況3.2.2
總結:可以發現我們沒有遺漏任何情況,所有可能面臨的情況我們都處理了
五.紅黑樹之刪除結點
先說一個刪除結點的過程原理:首先將紅黑樹當作一個二叉查找樹,將該結點從二叉查找樹種刪除,然后通過一些列重新着色操作等一系列措施來修正該樹,使之重新成為一顆紅黑樹
刪除結點其實很容易,難的是如何使得刪除結點后的樹重新成為一個紅黑樹
我們可以根據刪除結點N的兒子個數分為三種情況:
1.刪除結點沒有兒子
2.刪除結點有1個兒子
3.刪除結點有2個兒子
接下來我們又可以對以上三種情況繼續進行細分
一.刪除結點沒有兒子的情況:
1)刪除結點為紅色
2)刪除結點為黑色,其兄弟結點沒有兒子
3)刪除結點為黑色,其兄弟結點有一個孩子不空,並且該孩子為右孩子
4)刪除結點為黑色,其兄弟結點有一個孩子不空,並且該孩子為左孩子
5)刪除結點為黑色,其兄弟結點有兩個孩子,而且兄弟結點為紅色
6)刪除結點為黑色,其兄弟結點有兩個孩子,而且兄弟結點為黑色
二.刪除結點只有一個兒子的情況:
1)刪除結點為黑色,其唯一的兒子結點為紅色(必定是紅色,要不然不符合紅黑樹的第5條性質)
2)刪除結點為紅色,其兒子結點只能為黑:紅黑樹中不存在這種情況,要不然無法滿足紅黑樹第5條性質
三.刪除結點有兩個兒子的情況:
現在我們就具體分析一下面臨不同的操作到達該這么操作:
一.刪除結點沒有兒子的情況:
1)刪除結點為紅色
直接刪除,比如下圖,想要刪除130結點
圖14
直接刪除130結點,結果圖如下:
圖15
因為刪除的是紅色結點,不會影響紅黑樹第5條性質,所以可以直接刪除
2)刪除結點為黑色,其兄弟結點沒有兒子
這種情況下其兄弟結點也肯定是黑色的(要滿足紅黑樹第5條性質),假設現在要刪除的是150這個結點,原圖如下:
圖16
先刪除結點150,然后將兄弟結點126變成紅色,父親結點140變成黑色,結果如下:
圖17
這樣做的目的是為了滿足紅黑樹的第5條性質,要不然根到最右邊的葉子結點經過的黑色結點只有3個,而其他路徑有4個
3)刪除結點為黑色,其兄弟結點有一個孩子不空,並且該孩子和兄弟結點在同一邊(同為左子樹或者同為右子樹)
假設現在要刪除的結點為110,其兄弟結點140只有一個孩子150,而且都是右子樹,滿足上述條件,原圖如下:
圖18
先把需要刪除的結點110刪除,然后這個時候需要交換兄弟結點140和父親結點120的顏色,並且把父親結點120塗成黑色,把兄弟結點的子節點150塗成黑色
1.如果兄弟結點和兄弟結點的兒子都在右子樹的話:對父親結點進行左旋
2.如果兄弟結點和兄弟結點的兒子都在左子樹的話:對父親結點進行右旋
上圖是第一種情況,所以對父結點120進行左旋,結果如下:
圖19
通過對某些結點重新着色和旋轉,又將該樹變成了一個標准的紅黑樹了
4)刪除結點為黑色,其兄弟結點有一個孩子不空,並且該孩子和兄弟結點不在同一邊(右左或者左右的情況)
(這種情況下,兄弟結點的兒子50結點只能為紅色,要不然滿足不了紅黑樹的第5條性質)
假設我們現在要刪除的結點是80結點,其兄弟結點只有一個兒子,而且兄弟結點和兄弟結點的兒子是左右的情況(兄弟結點為左結點,兄弟結點的兒子為右結點),符合上述要求,原圖如下:
圖20
現在我們先將需要刪除的80結點刪除,然后將兄弟結點和兄弟結點的兒子結點顏色互換
如果兄弟結點是左子樹,兄弟結點的兒子結點是右子樹:對兄弟結點進行左旋
如果兄弟結點是右子樹,兄弟結點的兒子結點是左子樹:對兄弟結點進行右旋
上圖的情況是進行左旋,也就是對兄弟結點30進行左旋,結果如下圖:
圖21
注意!!,現在還沒有結束變換,我們發現變換之后的紅黑樹情況和情況3中的情況很相似,兄弟結點50和兄弟結點的子節點30處在同一邊,我們可以按照情況3的處理辦法進行處理:
交換兄弟結點50和父親結點60的顏色,把父親結點60和兄弟結點的子節點30塗成黑色
1.如果兄弟結點和兄弟結點的兒子都在右子樹的話:對父親結點進行左旋
2.如果兄弟結點和兄弟結點的兒子都在左子樹的話,對父親結點進行右旋
上圖的情況是第2中,所以對父親結點60進行右旋,結果如下:
圖22
5)刪除結點為黑色,其兄弟結點有兩個孩子,兄弟結點為黑色而且兩個孩子結點也為黑色
現在我們假設要刪除的結點是130結點,其兄弟結點有兩個孩子(可以把空的葉子結點看成黑色的兒子結點),而且兄弟結點和兄弟結點的兒子結點都是黑色,符合上述情況,原圖如下:
圖23
先直接刪除需要刪除的結點130,然后將父親結點140和兄弟結點150顏色互換即可,結果如下:
圖24
6)刪除結點為黑色,其兄弟結點有兩個孩子,而且兄弟結點為紅色
假設我們要刪除的結點是110,其兄弟結點140為紅色而且有兩個孩子,原圖如下:
圖25
我們先交換兄弟結點140和父親結點120的顏色
1.被刪除的元素為左子樹:對父親結點左旋
2.被刪除的元素為右子樹:對父親結點右旋
上圖的情況是第一種情況,所以我們對父親結點140進行左旋,按照上面操作之后(未完),結果如下:
圖26
我們發現完成上述操作之后樹還不是一個標准的紅黑樹(到葉子結點的一條路徑黑色結點只有3個,而其他的路徑有4個),我們發現現在紅黑樹的情況又和情況5的很像,所以我們按照情況5的做法繼續:
我們要需要刪除的結點還沒有被刪除(我特意留到最后刪除的,就是為了在這里表示父親結點是誰的父親結點...),現在我們將父親結點120和兄弟結點130的顏色互換即可,結果如下:
圖27
我們現在對刪除結點沒有兒子結點的6種刪除情況進行一下總結:
刪除結點沒有兒子結點:
1)刪除結點為紅色:
直接刪除
2)刪除結點為黑色,其兄弟結點沒有兒子:
兄弟結點變紅,父親結點變黑,然后將父親結點當作當前結點按照這幾種情形處理,直到當前結點為根結點
3)刪除結點為黑色,其兄弟結點有一個孩子不空,並且該孩子和兄弟結點在同一邊(同為左子樹或者同為右子樹):
1.不管是括號中那種情況,先交換兄弟結點和父親結點的顏色,並且把父親結點和兄弟結點的子結點塗成黑色
2.1如果兄弟結點和兄弟結點的兒子都在右子樹的話:對父親結點進行左旋
2.2如果兄弟結點和兄弟結點的兒子都在左子樹的話:對父親結點進行右旋
4)刪除結點為黑色,其兄弟結點有一個孩子不空,並且該孩子和兄弟結點不在同一邊(右左或者左右的情況):
1.先將兄弟結點和兄弟結點的兒子結點顏色互換
2.1如果兄弟結點是左子樹,兄弟結點的兒子結點是右子樹:對兄弟結點進行左旋
2.2如果兄弟結點是右子樹,兄弟結點的兒子結點是左子樹:對兄弟結點進行右旋
3.將后續變換按照第3條處理
5)刪除結點為黑色,其兄弟結點有兩個孩子,兄弟結點為黑色而且兩個孩子結點也為黑色:
1.將父親結點和兄弟結點顏色互換
6)刪除結點為黑色,其兄弟結點有兩個孩子,而且兄弟結點為紅色:
1.將兄弟結點和父親結點的顏色互換
2.1 被刪除的元素為左子樹:對父親結點左旋
2.2 被刪除的元素為右子樹:對父親結點右旋
3.將后續變換按照第5條進行處理
以上6種情況討論的都是刪除結點沒有兒子的情況(空葉子結點不算兒子結點)
現在我們來看看刪除結點僅有一個兒子結點的情況!
二.刪除結點僅有一個兒子結點的情況
1)刪除結點為黑色,兒子結點無論左右都可以
比如我們要刪除的結點是120結點,刪除結點為黑色,唯一的兒子結點130為紅色(必須是紅色,不然違背紅黑樹第5條性質)原圖如下:
圖28
我們將需要刪除的結點120刪除,然后將子節點130塗黑放到被刪除結點120的位置,結果如下:
圖29
2)刪除結點為紅色:其兒子結點只能為黑,紅黑樹中不存在這種情況,要不然無法滿足紅黑樹第5條性質
總結一下刪除結點只有一個兒子的情況:
1)刪除結點為黑色,兒子結點無論左右都可以
將兒子結點塗成黑色放到被刪除結點的位置
下面我們來看看刪除結點有兩個兒子結點的情況
三.刪除結點有兩個兒子結點
找到刪除結點的右子樹中最左的結點,兩兩值交換,然后刪除結點的情況就變成了上面兩種情況中的一種了
1.刪除結點只有一個兒子的情況
2.刪除結點沒有兒子的情況
比如下圖
圖30
假設要刪除的結點是120,先找到結點120右子樹中最左的結點125,交換兩者的值,圖如下:
圖31
現在120仍然是要刪除的結點,我們發現刪除結點120沒有一個兒子,而且其兄弟結點也沒有兒子,那么其對應的情況為:
2)刪除結點為黑色,其兄弟結點沒有兒子:
兄弟結點變紅,父親結點變黑
經過上面的變形,結果如下:
圖32
經過變換,該樹變成了一顆標准的紅黑樹
所以當刪除結點右兩個兒子結點的時候,我們只需要按照搜索二叉樹的刪除方法替換刪除值,這樣就可以將情況變成刪除結點沒有兒子結點或者1個兒子結點的情況處理了
--------------------------------------------------------------------------------------------------
這是一條有底線的底線哦!






























