查閱了不少的資料,最終把紅黑樹的刪除操做弄明白。爲方便往後溫習,也爲那些正想弄明白但又苦苦明白不了該操做詳細原理的同窗查閱,特將其當筆記記錄下來。下面內容是我的所理解的紅黑樹的刪除操做,若是有不對的地方,歡迎各路大神指正。spa
紅黑樹的刪除操做blog
1:節點命名約定效率
D表示要被刪除的節點。即:取 Delete 的首字母;原理
P 表示父節點。即:取 Parent 的首字母;搜索
S表示兄弟姐妹節點。即:取 Sibling的首字母;im
U表示叔伯節點。即:取Uncle的首字母;命名
G表示祖父節點。即:取 Grandfather的首字母;db
L表示左樹。即:取Left的首字母;img
R表示右樹。即:取Right的首字母;紅黑樹
Nil表示葉子節點。即所謂的空節點;注意:紅黑樹中的葉子節點與其餘樹中所述說的葉子節點不是同一律念。並且紅黑樹中的葉子節點(即:Nil節點)永遠是被定義爲黑色的。
下文的節點命名錶示將會使用以上這些命名約定或它們的組合表示。所以,請先牢記這些命名約定。舉例:
DR表示要被刪除的節點的右子樹,即:右子節點;
SL表示兄弟節點的左子樹,即:左子節點;
…
2:刪除操做宏觀分析
在紅黑樹中,刪除一個節點往大的說,只有如下四種狀況。
狀況一:刪除的節點的左、右子樹都非空;
狀況二:刪除的節點的左子樹爲空樹,右子樹非空;
狀況三:刪除的節點的右子樹爲空樹,左子樹非空;
狀況四:刪除的節點的左、右子樹都爲空樹;
其中狀況一,能夠按與其餘二叉搜索樹的刪除方式同樣處理,最終能夠轉換到後面的三種狀況。具體爲:找到(Old)D節點的直接後繼節點(暫且稱爲X節點),而後將X的值轉移到D節點,最後將X節點做爲真正要被刪除掉的節點(即:(Real)D節點)。這樣刪除操做後,能夠保證該樹仍然爲一棵二叉搜索樹。但因爲紅黑樹的定義(即:紅黑樹的性質)約定。這樣刪除(Real)D節點後,可能會破壞紅黑樹的性質。因此須要額外作一些調整處理,這即是下面將要詳細討論的內容。
說明:下文中所提到的D,除非有特別說明,不然都將指的是(Real)D。
3:紅黑樹刪除後平衡處理
在具體分析以前,再次列出紅黑樹的定義:
1) 任何一個節點非紅即黑;
2) 樹的根爲黑色;
3) 葉子節點爲黑色(注意:紅黑樹的全部葉子節點都指的是Nil節點);
4) 任何兩個父子節點不可能同時爲紅色;
5) 任何節點到其全部分枝葉子的簡單路徑上的黑節點個數相同;
下面是幾個圖示說明:
根據紅黑樹的定義,被刪除的節點D(即:上文所述的(Real)D節點)不論如何都必定有一個「右子樹」,只是該右子樹要不爲非空樹(即:真正存在的節點,不爲Nil節點),要不就必爲空樹(即:D的兩個子節點都爲Nil)。下面稱D的該右子節點(或稱爲右子樹)爲DR。
a) 被刪除的D節點爲紅色。這種狀況,則與D相關的顏色以及結構關係必然只有以下一種狀況(爲何只有這種狀況,不明白的請看紅黑樹的性質):
分析:由於D爲紅色,因此P必爲黑色,同時DR不可能爲紅色(不然違反性質4)。同時因爲性質5,則DR必爲Nil,不然就D樹來講,通過DR與不通過DR的路徑的黑節點數必不相同。如今要刪除D節點,只須要直接將D節點刪除,並將DR做爲P的左子節點便可。所以刪除後,變成上圖右側所示。
b) 被刪除的D節點爲黑色。此時狀況會稍複雜些,具體又分析爲:DR爲Nil與DR不爲Nil。根據性質5,若是DR不爲Nil,則DR必爲紅色,且DR的兩個子節點必爲Nil。所以,此處先來分析DR不爲Nil的狀況(由於該狀況比較簡單)。而DR爲Nil的狀況,由後面的C)及其後內容再進行具體分析 。
如前所述,若是DR不爲Nil,則D、DR必爲以下狀況:
分析:因爲刪除的D爲黑色,刪除後P的左子樹的黑節點數必少1,此時恰好DR爲黑色,而且刪除後DR能夠佔據D的位置(這樣還是一棵二叉搜索樹,只是暫時還不是合格的紅黑樹罷了),而後再將DR的顏色改成黑色,恰好能夠填補P左子樹所減小的黑節點數。從而P樹又平衡了。所以,平衡處理後,最終變成上圖右側的圖示。
c) 被刪除的D爲黑色,且DR爲Nil。
若是DR爲Nil,則刪除D後,P的左子樹黑節點數一定少1,純粹想在P的左子樹作文章來平衡P樹是絕無可能的了。所以,一定須要其餘分支的輔助來最終完成平衡調整。根據紅黑樹的定義,P會有一個右子節點,稱爲S子節點。此處又可細節分兩種狀況:黑S與紅S。此處先討論紅S的狀況。
說明:若是S爲黑,則它必不會爲Nil。(不明白的人,再好好想一想爲何)。同時根據紅黑樹的性質,D、S、P、SL、SL的顏色關係必只有以下一種狀況(由於此處探討的是S爲紅的狀況)。
分析:刪除前P樹的左、右子樹的黑節點數平衡,刪除後(即:上圖右側所示),通過DR分支的黑節點數將比經過S分支的黑節點數少1。此時,作以下操做:
將P左旋轉,再將P由黑色改成紅色,將S由紅色改成黑色,演變過程以下圖示:
通過以上演變後,通過P的路徑,左分支黑節點數還是少1,其餘分支的黑節點數作仍然保持不變。此時的狀況卻變成DR的兄弟節點爲黑色(再也不是紅色的狀況了),所以轉入此處c)點一開始所說的另外一種狀況(S爲黑色的狀況)的處理。
提示:此時須要把 SR 節點當作原先的 S 節點。
注意:可能有人會一時想不明白什麼要這樣轉換。由於這樣轉換後,雖然對於P樹的左子樹的黑節點數仍然會比右子樹的黑節點數少1,但此時DR的兄弟(之前的S節點)如今已經變爲SL,即已經由紅色變爲黑色,而且很是重要的此時的DR的兄弟節點SL的子結點(即:DR的兩個侄子節點),要不就是紅色節點要不就必爲Nil節點,而這種狀況正是D爲黑色、S也黑色的狀況。(注意看注意看注意看必定注意看這點:對於被刪除節點D的父節點來講,D黑S黑的狀況下,不管如何D的兄弟節點S的兩個兒子節點SL與SR都不多是非Nil的黑節點。不明白的好好想一想爲何)。所以咱們有了進一步分析的餘地。
d) 被刪除的D爲黑色,S也爲黑色的狀況。根據D、P、S、SL、SR的顏色組合狀況,原本是有很是多種變換的。但事實上,咱們只須要按以下4種狀況作進一步的處理,便可所有涵蓋全部的顏色組合狀況。
d.1> SL爲紅,SR顏色任意;(對於該狀況的處理,其實咱們不關心P的顏色)
d.2> SR爲紅,SL顏色任意;(對於該狀況的處理,其實咱們不關心P的顏色)
d.3> SL、SR都爲黑;P爲紅。(注意:根據前面c)點的紅色文字部分的分析,此時SL與SR一定一定都爲Nil節點);
d.4> SL、SR都爲黑;P爲黑。(注意:根據前面c)點的紅色文字部分的分析,此時SL與SR一定一定都爲Nil節點);
d.1> SL爲紅,SR顏色任意狀況
分析:P樹的左子樹黑節點數減小1,所以,要想平衡,必需想辦法讓左子樹的黑結節數增長1,並且同時P的右子樹的黑節點數要保持不變。所以,想辦法將SL這個紅色節點利用起來,讓它來填補P的左子樹所缺乏的黑節點個數。所以,立馬想到旋轉,只要有辦法轉到P的左子樹或P位置上,則就有可能填平P左子樹的高度。因此具體操做步驟爲:
將S右旋轉;接着將SL改成P的顏色,P的顏色改成黑色(用這個黑色來填補DR分支的黑節點數);將P左旋轉。
d.2> SR爲紅色,SL顏色任意的狀況
分析:思路同d.1>狀況相似,都是想辦法用紅色的SR節點來填補P的左子樹的減小的黑節點數。具體步驟爲:
將S由黑色改成P的顏色;
將SR由紅色改成黑色;
將P的顏色改成黑色(用該黑色來填補DR分支缺失的黑節點數);
將P節點左旋轉;
d.3> SL、SR都爲黑色(其實都爲Nil節點),P爲紅色的狀況
分析:此狀況較爲簡單,直接將紅色的P改成黑色,以此爲填補DR缺乏的黑節點個數。此時P右子樹黑節點數卻增多,所以,再將S改成紅色便可平衡。
d.4> SL、SR都爲黑色(其實都爲Nil節點),P爲黑色的狀況
分析:由於DR、P、S、SL、SR全都爲黑色,則不論如何變換,都永遠不可能使用P的左右子樹的黑節點數達到平衡。而P不平衡的緣由是由於P的右子樹黑節點數會比左子樹多1個。所以,乾脆將S由黑色改成紅色,如此一來,P的左、右子樹的黑節點個數是平衡的。可是,此時通過P的路徑的黑節點個數將會比不通過它的路徑少一個。所以,咱們將P做爲待平衡的節點(即:此時的P至關於DR的角色)往上繼續上溯,直到P爲根節點爲止。
到此,紅黑樹的刪除操做已所有說明完。從以上的分析來看,紅黑樹的刪除操做將是最爲費時的,至少會比插入操做複雜,更耗時的可能性確定會更大。但事實上,紅黑樹的插入、刪除、效率都是很是高的。插入比較簡單就不說了。刪除操做事實上,就算遇到最壞狀況:DR、P、S、SL、SR全爲黑的狀況下,在上溯過程當中,通常狀況下也是會很快就遇到紅色的P節點的。除非整棵紅黑樹的右子樹基本上都是黑節點(試想下,這可能性幾乎不可能,由於咱們插入時,老是以紅色插入的,再加上紅黑樹的幾條性質約束一下),或者原本身紅黑樹的總體高度就很是淺。
以上是我的的理解,歡迎指正。