紅黑樹

 

介紹還有一種平衡二叉樹:紅黑樹(Red Black Tree),紅黑樹由Rudolf Bayer1972年發明,當時被稱爲平衡二叉B樹(symmetric binary B-trees),1978年被Leonidas J. Guibas Robert Sedgewick改爲一個比較摩登的名字:紅黑樹。html

紅黑樹和以前所講的AVL樹類似,都是在進行插入和刪除操做時經過特定操做保持二叉查找樹的平衡,從而得到較高的查找性能。自從紅黑樹出來後,AVL樹就被放到了博物館裏,聽說是紅黑樹有更好的效率,更高的統計性能。只是在我瞭解了紅黑樹的實現原理後,並不相信這是真的,關於這一點咱們會在後面進行討論。算法

紅黑樹和AVL樹的差異在於它使用顏色來標識結點的高度,它所追求的是局部平衡而不是AVL樹中的很嚴格的平衡。以前咱們在解說AVL樹時,已經領教過AVL樹的複雜,但AVL樹的複雜比起紅黑樹來講簡直是小巫見大巫。紅黑樹是真正的變態級數據結構。數據結構

首先來一個Silverlight作的紅黑樹的動畫,它有助於幫你理解什麼是紅黑樹。這裏需要注意,必須安裝Silverlight 2.0 RTW 才幹正常執行遊戲,下載地址:性能

http://www.microsoft.com/silverlight/resources/install.aspx?v=2.0動畫

 

使用注意事項:ui

l         結點僅僅接收整數,假設在加入和刪除操做中輸入非法字串,則會隨機加入或刪除一個0~99之間的整數。spa

l         可以不在編輯框中輸入數字,直接單擊加入和刪除button進行加入和刪除操做。.net

l         可以拖動拖動條控制動畫速度。設計

紅黑樹的平衡

紅黑樹首先是一棵二叉查找樹,它每個結點都被標上了顏色(紅色或黑色),紅黑樹知足下面5個性質:指針

一、 每個結點的顏色僅僅能是紅色或黑色。

二、 根結點是黑色的。

三、 每個葉子結點都帶有兩個空的黑色結點(被稱爲黑哨兵),假設一個結點n的僅僅有一個左孩子,那麼n的右孩子是一個黑哨兵;假設結點n僅僅有一個右孩子,那麼n的左孩子是一個黑哨兵。

四、 假設一個結點是紅的,則它的兩個兒子都是黑的。也就是說在一條路徑上不能出現相鄰的兩個紅色結點。

五、 對於每個結點來講,從該結點到其子孫葉結點的所有路徑上包括一樣數目的黑結點。

紅黑樹的這5個性質中,第3點是比較難理解的,但它卻頗有必要。咱們看圖1中的左邊這張圖,假設不使用黑哨兵,它全然知足紅黑樹性質,結點50到兩個葉結點8和葉結點82路徑上的黑色結點數都爲2個。但假設增長黑哨兵後(如圖1右圖中的小黑圓點),葉結點的個數變爲8個黑哨兵,根結點50到這8個葉結點路徑上的黑高度就不同了,因此它並不是一棵紅黑樹。

 

 

要看真正的紅黑樹請在以上動畫中加入幾個結點,看看是否知足以上性質。

紅黑樹的旋轉操做

紅黑樹的旋轉操做和AVL樹同樣,分爲LLRRLRRL四種旋轉類型,區別在於旋轉完畢後改變的是結點的顏色,而不是平衡因子。旋轉動畫演示請參考AVL這篇文章中的Flash動畫:

http://www.cnblogs.com/abatei/archive/2008/11/17/1335031.html

紅黑樹上結點的插入

在討論紅黑樹的插入操做以前必須要明確,不論什麼一個即將插入的新結點的初始顏色都爲紅色。這一點很是easy理解,因爲插入黑點會添加某條路徑上黑結點的數目,從而致使整棵樹黑高度的不平衡。但假設新結點父結點爲紅色時(如圖2所看到的),將會違返紅黑樹性質:一條路徑上不能出現相鄰的兩個紅色結點。這時就須要經過一系列操做來使紅黑樹保持平衡。

 

 

 

爲了清楚地表示插入操做下面在結點中使用「新」字表示一個新插入的結點;使用「父」字表示新插入點的父結點;使用「叔」字表示「父」結點的兄弟結點;使用「祖」字表示「父」結點的父結點。插入操做分爲下面幾種狀況:

1黑父

如圖3所看到的,假設新點的父結點爲黑色結點,那麼插入一個紅點將不會影響紅黑樹的平衡,此時插入操做完畢。紅黑樹比AVL樹優秀的地方之中的一個在於黑父的狀況比較常見,從而使紅黑樹需要旋轉的概率相對AVL樹來講會少一些。

 

 

 

2.紅父

假設新點的父結點爲紅色,這時就需要進行一系列操做以保證整棵樹紅黑性質。如圖3所看到的,由於父結點爲紅色,此時可以斷定,祖父結點必然爲黑色。這時需要依據叔父結點的顏色來決定作什麼樣的操做。青色結點表示顏色未知。由於有可能需要根結點到新點的路徑上進行屢次旋轉操做,而每次進行不平衡推斷的起始點(咱們可將其視爲新點)都不同。因此咱們在此使用一個藍色箭頭指向這個起始點,並稱之爲斷定點。

 

 

 

2.1 紅叔

當叔父結點爲紅色時,如圖4所看到的,無需進行旋轉操做,僅僅要將父和叔結點變爲黑色,將祖父結點變爲紅色就能夠。但由於祖父結點的父結點有可能爲紅色,從而違反紅黑樹性質。此時必須將祖父結點做爲新的斷定點繼續向上進行平衡操做。

 

 

需要注意,無論「父」在「叔」的左邊仍是右邊,無論「新」是「父」的左孩子仍是右孩子,它們的操做都全然同樣。

 

2.2 黑叔

當叔父結點爲黑色時,需要進行旋轉,下面圖示了所有的旋轉可能

情形1

 

 

情形2

 

情形3

 

 

情形4

 

 

可以觀察到,當旋轉完畢後,新的旋轉根全部爲黑色,此時不需要再向上回溯進行平衡操做,插入操做完畢。需要注意,上面四張圖的「叔」、「1」、「2」、「3」結點有可能爲黑哨兵結點。

事實上紅黑樹的插入操做不是很是難,甚至比AVL樹的插入操做還更簡單些。但刪除操做就遠遠比AVL樹複雜得多,如下就介紹紅黑樹的刪除操做。

紅黑樹上結點的刪除

紅黑樹自己是一棵二叉查找樹,它的刪除和二叉查找樹的刪除類似。首先要找到真正的刪除點,當被刪除結點n存在左右孩子時,真正的刪除點應該是n的中序遍在前驅,關於這一點請複習二叉查找樹的刪除。如圖9所看到的,當刪除結點20時,實際被刪除的結點應該爲18,結點20的數據變爲18

 

 

 

因此可以判斷出,在進行刪除操做時,真正的刪除點必然是僅僅有一個孩子或沒有孩子的結點。而依據紅黑樹的性質可以得出下面兩個結論:

一、 刪除操做中真正被刪除的必然是僅僅有一個紅色孩子或沒有孩子的結點

二、 假設真正的刪除點是一個紅色結點,那麼它必然是一個葉子結點

理解這兩點很重要,如圖10所看到的,除了狀況(a)外,其它任一種況結點N都沒法知足紅黑樹性質。

 

 

 

在下面討論中,咱們使用藍色箭頭表示真正的刪除點,它也是旋轉操做過程當中的第一個斷定點;真正的刪除點使用「舊」標註,舊點所在位置將被它的的孩子結點所代替(最多僅僅有一個孩子),咱們使用「新」表示舊點的孩子結點。刪除操做可分爲下面幾種情形:

1、舊點爲紅色結點

若舊點爲紅色結點,則它必然是葉子結點,直接刪除就能夠。如圖11所看到的

 

 

 

2、一紅一黑

當舊點爲黑色結點,新點爲紅色結點時,將新點代替舊點位置後,將新點染成黑色就能夠(如圖12所看到的)。這裏需要注意:舊點爲紅色,新點爲黑色的狀況不可能存在。

 

 

 

3、雙黑

當舊點和新點都爲黑色時(新點爲空結點時,亦屬於這樣的狀況),狀況比較複雜,需要依據舊點兄弟結點的顏色來決定進行什麼樣的操做。咱們使用「兄」來表示舊點的兄弟結點。這裏可分爲紅兄和黑兄兩種狀況:

3.1 紅兄

由於兄弟結點爲紅色,因此父結點必然爲黑色,而舊點被刪除後,新點代替了它的位置。下圖演示了兩種可能的狀況:

 

 

 

紅兄的狀況需要進行RRLL型旋轉,而後將父結點染成紅色,兄結點染成黑色。而後又一次以新點爲斷定點進行平衡操做。咱們可以觀察到,旋轉操做完畢後,斷定點沒有向上回溯,而是減小了一層,此時變成了黑兄的狀況。

3.2 黑兄

黑兄的狀況最爲複雜,需要依據黑兄孩子結點(這裏用「侄」表示)和父親結點的顏色來決定作什麼樣的操做。

3.2.1 黑兄二黑侄紅父

如圖14所看到的,這樣的狀況比較簡單,僅僅需將父結點變爲黑色,兄結點變爲黑色,新結點變爲黑色就能夠,刪除操做到此結束。

 

 

 

3.2.2 黑兄二黑侄黑父

如圖15所看到的,此時將父結點染成新結點的顏色,新結點染成黑色,兄結點染成紅色就能夠。當新結點爲紅色時,父結點被染成紅色,此時需要以父結點爲斷定點繼續向上進行平衡操做。

 

 

 

3.2.3 黑兄紅侄

黑兄紅侄有如下四種情形,如下分別進行圖示:

情形1

 

 

情形2

 

情形3

 

情形4

 

 

 

由以上圖例所看到的,看完以上四張圖的兄弟有可能會有一個疑問,假設情形1和情形2中的兩個侄子結點都爲紅色時,是該進行LL旋轉仍是進行LR旋轉呢?答案是進行LL旋轉。情形3和情形4則是優先進行RR旋轉的斷定。

 

 

 

 

 

 

 

 

    教你透徹瞭解黑樹

 

做者 July、saturnman   2010年12月29日

本文參考:Google、算法導論、STL源代碼剖析、計算機程序設計藝術。
本人聲明:我的原創,轉載請註明出處。

推薦閱讀:Left-Leaning Red-Black TreesDagstuhl Workshop on Data Structures, Wadern, Germany, February, 2008.

------------------------------
紅黑樹系列,四篇文章於今日已經完畢。[二零一一年一月九日]

教你透徹瞭解紅黑樹:
http://blog.csdn.net/v_JULY_v/archive/2010/12/29/6105630.aspx
紅黑樹算法的層層剖析與逐步實現  [此文被推薦]
http://blog.csdn.net/v_JULY_v/archive/2010/12/31/6109153.aspx
教你完全實現紅黑樹:紅黑樹的c源代碼實現與剖析
http://blog.csdn.net/v_JULY_v/archive/2011/01/03/6114226.aspx
一步一圖一代碼,必定要讓你真正完全明確紅黑樹 [最後更新]
http://blog.csdn.net/v_JULY_v/archive/2011/01/09/6124989.aspx

------------------------------

 

1、紅黑樹的介紹

先來看下算法導論對R-B Tree的介紹:
紅黑樹,一種二叉查找樹,但在每個結點上添加一個存儲位表示結點的顏色,可以是Red或Black。
經過對不論什麼一條從根到葉子的路徑上各個結點着色方式的限制,紅黑樹確保沒有一條路徑會比其
他路徑長出倆倍,於是是接近平衡的。

 

前面說了,紅黑樹,是一種二叉查找樹,既然是二叉查找樹,那麼它必知足二叉查找樹的通常性質。
如下,在詳細介紹紅黑樹以前,我們先來了解下 二叉查找樹的通常性質:
1.在一棵二叉查找樹上,運行查找、插入、刪除等操做,的時間複雜度爲O(lgn)。
    因爲,一棵由n個結點,隨機構造的二叉查找樹的高度爲lgn,因此瓜熟蒂落,通常操做的運行時間爲O(lgn)。
    //至於n個結點的二叉樹高度爲lgn的證實,可參考算法導論 第12章 二叉查找樹 第12.4節。
2.但如果一棵具備n個結點的線性鏈,則此些操做最壞狀況運行時間爲O(n)。

 

紅黑樹,能保證在最壞狀況下,主要的動態幾何操做的時間均爲O(lgn)。

ok,咱們知道,紅黑樹上每個結點內含五個域,color,key,left,right。假設對應的指針域沒有,則設爲NIL。

通常的,紅黑樹,知足下面性質,即僅僅有知足下面全部性質的樹,咱們才稱之爲紅黑樹:

1)每個結點要麼是紅的,要麼是黑的。
2)根結點是黑的。
3)每個葉結點,即空結點(NIL)是黑的。
4)假設一個結點是紅的,那麼它的倆個兒子都是黑的。
5)對每個結點,從該結點到其子孫結點的所有路徑上包括一樣數目的黑結點。

 

下圖所看到的,便是一顆紅黑樹:

此圖忽略了葉子和根部的父結點。

 

2、樹的旋轉知識

當咱們在對紅黑樹進行插入和刪除等操做時,對樹作了改動,那麼可能會違背紅黑樹的性質。

爲了保持紅黑樹的性質,咱們可以經過對樹進行旋轉,即改動樹種某些結點的顏色及指針結構,以達到對紅黑樹進行

插入、刪除結點等操做時,紅黑樹依舊能保持它特有的性質(如上文所述的,五點性質)。

 

樹的旋轉,分爲左旋和右旋,下面藉助圖來作形象的解釋和介紹:

1.左旋

如上圖所看到的:

當在某個結點pivot上,作左旋操做時,咱們若是它的右孩子y不是NIL[T],pivot可以爲樹內隨意右孩子而不是NIL[T]的結點。

左旋以pivot到y之間的鏈爲「支軸」進行,它使y成爲該孩子樹新的根,而y的左孩子b則成爲pivot的右孩子。

來看算法導論對此操做的算法實現(以x取代上述的pivot):

 LEFT-ROTATE(Tx)
1  y  right[x Set y.
2  right[x left[y]       Turn y's left subtree into x's right subtree.

3  p[left[y]]  x
4  p[y p[x]              Link x's parent to y.
5  if p[x] = nil[T]
6     then root[T y
7     else if x = left[p[x]]
8             then left[p[x]]  y
9             else right[p[x]]  y
10  left[y x              Put x on y's left.
11  p[x y

 

2.右旋

右旋與左旋差點兒相同,再此不作具體介紹。

 

對於樹的旋轉,能保持不變的僅僅有原樹的搜索性質,而原樹的紅黑性質則不能保持,

在紅黑樹的數據插入和刪除後可利用旋轉和顏色重塗來恢復樹的紅黑性質。

 

至於有些書如 STL源代碼剖析有對雙旋的描寫敘述,事實上雙旋僅僅是單旋的兩次應用,並沒有新的內容,

所以這裏就再也不介紹了,而且左右旋也是相互對稱的,僅僅要理解當中一種旋轉就可以了。

 

3、紅黑樹插入、刪除操做的詳細實現

   3、I、ok,接下來,我們來詳細瞭解紅黑樹的插入操做。
向一棵含有n個結點的紅黑樹插入一個新結點的操做可以在O(lgn)時間內完畢。

算法導論:
RB-INSERT(T, z)
 1  y ← nil[T]
 2  x ← root[T]
 3  while x ≠ nil[T]
 4      do y ← x
 5         if key[z] < key[x]
 6            then x ← left[x]
 7            else x ← right[x]
 8  p[z] ← y
 9  if y = nil[T]
10     then root[T] ← z
11     else if key[z] < key[y]
12             then left[y] ← z
13             else right[y] ← z
14  left[z] ← nil[T]
15  right[z] ← nil[T]
16  color[z] ← RED
17  RB-INSERT-FIXUP(T, z)

我們來詳細分析下,此段代碼:
RB-INSERT(T, z),將z插入紅黑樹T 以內。

爲保證紅黑性質在插入操做後依舊保持,上述代碼調用了一個輔助程序RB-INSERT-FIXUP
來對結點進行又一次着色,並旋轉。

14  left[z] ← nil[T]
15  right[z] ← nil[T]  //保持正確的樹結構
第16行,將z着爲紅色,由於將z着爲紅色可能會違背某一條紅黑樹的性質,
因此,在第17行,調用RB-INSERT-FIXUP(T,z)來保持紅黑樹的性質。

RB-INSERT-FIXUP(T, z),例如如下所看到的:
 1 while color[p[z]] = RED
 2     do if p[z] = left[p[p[z]]]
 3           then y ← right[p[p[z]]]
 4                if color[y] = RED
 5                   then color[p[z]] ← BLACK                    ▹ Case 1
 6                        color[y] ← BLACK                       ▹ Case 1
 7                        color[p[p[z]]] ← RED                   ▹ Case 1
 8                        z ← p[p[z]]                            ▹ Case 1
 9                   else if z = right[p[z]]
10                           then z ← p[z]                       ▹ Case 2
11                                LEFT-ROTATE(T, z)              ▹ Case 2
12                           color[p[z]] ← BLACK                 ▹ Case 3
13                           color[p[p[z]]] ← RED                ▹ Case 3
14                           RIGHT-ROTATE(T, p[p[z]])            ▹ Case 3
15           else (same as then clause
                         with "right" and "left" exchanged)
16 color[root[T]] ← BLACK

 
ok,參考一網友的言論,用本身的語言,再來詳細解剖下上述倆段代碼。
爲了保證闡述清晰,我再寫下紅黑樹的5個性質:

1)每個結點要麼是紅的,要麼是黑的。
2)根結點是黑的。
3)每個葉結點,即空結點(NIL)是黑的。
4)假設一個結點是紅的,那麼它的倆個兒子都是黑的。
5)對每個結點,從該結點到其子孫結點的所有路徑上包括一樣數目的黑結點。

 

在對紅黑樹進行插入操做時,咱們通常老是插入紅色的結點,因爲這樣可以在插入過程當中儘可能避免對樹的調整。
那麼,咱們插入一個結點後,可能會使原樹的哪些性質改變列?
因爲,咱們是依照二叉樹的方式進行插入,所以元素的搜索性質不會改變。

假設插入的結點是根結點,性質2會被破壞,假設插入結點的父結點是紅色,則會破壞性質4。
所以,總而言之,插入一個紅色結點僅僅會破壞性質2或性質4。
咱們的回覆策略很是簡單,
其1、把出現違背紅黑樹性質的結點向上移,假設能移到根結點,那麼很是easy就能經過直接改動根結點來恢復紅黑樹的性質。直接經過改動根結點來恢復紅黑樹應知足的性質。
其2、窮舉所有的可能性,以後把能歸於同一類方法處理的歸爲同一類,不能直接處理的化歸到如下的幾種狀況,

 //注:下面狀況三、四、5與上述算法導論上的代碼RB-INSERT-FIXUP(T, z),相相應:

 

狀況1:插入的是根結點。
原樹是空樹,此狀況僅僅會違反性質2。
  對策:直接把此結點塗爲黑色。
狀況2:插入的結點的父結點是黑色。
此不會違反性質2和性質4,紅黑樹沒有被破壞。
  對策:什麼也不作。
狀況3:當前結點的父結點是紅色且祖父結點的還有一個子結點(叔叔結點)是紅色。
此時父結點的父結點必定存在,不然插入前就已不是紅黑樹。
與此同一時候,又分爲父結點是祖父結點的左子仍是右子,對於對稱性,咱們僅僅要解開一個方向就可以了。

在此,咱們僅僅考慮父結點爲祖父左子的狀況。
同一時候,還可以分爲當前結點是其父結點的左子仍是右子,但是處理方式是同樣的。咱們將此歸爲同一類。
  對策:將當前節點的父節點和叔叔節點塗黑,祖父結點塗紅,把當前結點指向祖父節點,重新的當前節點又一次開始算法。

針對狀況3,變化前(圖片來源:saturnman)[插入4節點]:

變化後:

狀況4:當前節點的父節點是紅色,叔叔節點是黑色,當前節點是其父節點的右子

對策:當前節點的父節點作爲新的當前節點,以新當前節點爲支點左旋。

例如如下圖所看到的,變化前[插入7節點]:

 

變化後:

 

 

狀況5:當前節點的父節點是紅色,叔叔節點是黑色,當前節點是其父節點的左子

解法:父節點變爲黑色,祖父節點變爲紅色,在祖父節點爲支點右旋

例如如下圖所看到的[插入2節點]

變化後:

 

 

==================

   3、II、ok,接下來,我們最後來了解,紅黑樹的刪除操做:

算法導論一書,給的算法實現: 

RB-DELETE(T, z)   單純刪除結點的總操做
 1 if left[z] = nil[T] or right[z] = nil[T]
 2    then y ← z
 3    else y ← TREE-SUCCESSOR(z)
 4 if left[y] ≠ nil[T]
 5    then x ← left[y]
 6    else x ← right[y]
 7 p[x] ← p[y]
 8 if p[y] = nil[T]
 9    then root[T] ← x
10    else if y = left[p[y]]
11            then left[p[y]] ← x
12            else right[p[y]] ← x
13 if y 3≠ z
14    then key[z] ← key[y]
15         copy y's satellite data into z
16 if color[y] = BLACK
17    then RB-DELETE-FIXUP(T, x)
18 return y

 

RB-DELETE-FIXUP(T, x)   恢復與保持紅黑性質的工做
 1 while x ≠ root[T] and color[x] = BLACK
 2     do if x = left[p[x]]
 3           then w ← right[p[x]]
 4                if color[w] = RED
 5                   then color[w] ← BLACK                        ▹  Case 1
 6                        color[p[x]] ← RED                       ▹  Case 1
 7                        LEFT-ROTATE(T, p[x])                    ▹  Case 1
 8                        w ← right[p[x]]                         ▹  Case 1
 9                if color[left[w]] = BLACK and color[right[w]] = BLACK
10                   then color[w] ← RED                          ▹  Case 2
11                        x p[x]                                  ▹  Case 2
12                   else if color[right[w]] = BLACK
13                           then color[left[w]] ← BLACK          ▹  Case 3
14                                color[w] ← RED                  ▹  Case 3
15                                RIGHT-ROTATE(T, w)              ▹  Case 3
16                                w ← right[p[x]]                 ▹  Case 3
17                         color[w] ← color[p[x]]                 ▹  Case 4
18                         color[p[x]] ← BLACK                    ▹  Case 4
19                         color[right[w]] ← BLACK                ▹  Case 4
20                         LEFT-ROTATE(T, p[x])                   ▹  Case 4
21                         x ← root[T]                            ▹  Case 4
22        else (same as then clause with "right" and "left" exchanged)
23 color[x] ← BLACK

 

爲了保證下面的介紹與闡述清晰,我第三次重寫下紅黑樹的5個性質

1)每個結點要麼是紅的,要麼是黑的。
2)根結點是黑的。
3)每個葉結點,即空結點(NIL)是黑的。
4)假設一個結點是紅的,那麼它的倆個兒子都是黑的。
5)對每個結點,從該結點到其子孫結點的所有路徑上包括一樣數目的黑結點。

(相信,重述了3次,你應該有深入記憶了。:D)

 

 saturnman:
紅黑樹刪除的幾種狀況:

-------------------------------------------------
博主提醒:
下面所有的操做,是針對紅黑樹已經刪除結點以後,
爲了恢復和保持紅黑樹原有的5點性質,所作的恢復工做。

前面,我已經說了,因爲插入、或刪除結點後,
可能會違背、或破壞紅黑樹的原有的性質,
因此爲了使插入、或刪除結點後的樹依舊維持爲一棵新的紅黑樹,
那就要作倆方面的工做:
一、部分結點顏色,又一次着色
二、調整部分指針的指向,即左旋、右旋。

而如下所有的文字,則是針對紅黑樹刪除結點後,所作的修復紅黑樹性質的工做。

 二零一一年一月七日更新
------------------------------------------------------------

(注:下面的狀況三、四、五、6,與上述算法導論之代碼RB-DELETE-FIXUP(T, x) 恢復與保持
中case1,case2,case3,case4相相應。)
狀況1:當前節點是紅色
    解法,直接把當前節點染成黑色,結束。
    此時紅黑樹性質全部恢復。
狀況2:當前節點是黑色且是根節點
    解法:什麼都不作,結束

狀況3:當前節點是黑色,且兄弟節點爲紅色(此時父節點和兄弟節點的子節點分爲黑)。
    解法:把父節點染成紅色,把兄弟結點染成黑色,以後又一次進入算法(咱們僅僅討論當前節點是其父節點左孩子時的狀況)。
    而後,針對父節點作一次左旋。此變換後原紅黑樹性質5不變,而把問題轉化爲兄弟節點爲黑色的狀況。

                     3.變化前:

 

                     3.變化後: 

 

狀況4:當前節點是黑色,且兄弟是黑色,且兄弟節點的兩個子節點全爲黑色。
      解法:把當前節點和兄弟節點中抽取一重黑色追加到父節點上,把父節點當成新的當前節點,又一次進入算法。(此變換後性質5不變)

                        4.變化前

 

                        4.變化後

 

狀況5:當前節點顏色是黑色,兄弟節點是黑色,兄弟的左子是紅色,右子是黑色。
    解法:把兄弟結點染紅,兄弟左子節點染黑,以後再在兄弟節點爲支點解右旋,
以後又一次進入算法。此是把當前的狀況轉化爲狀況6,而性質5得以保持。

              5.變化前:

 

                  5.變化後:

 

狀況6:當前節點顏色是黑色,它的兄弟節點是黑色,但是兄弟節點的右子是紅色,兄弟節點左子的顏色隨意。

    解法:把兄弟節點染成當前節點父節點的顏色,把當前節點父節點染成黑色,兄弟節點右子染成黑色,

以後以當前節點的父節點爲支點進行左旋,此時算法結束,紅黑樹所有性質調整正確。

                    6.變化前:

              6.變化後:

 

限於篇幅,再也不過多贅述。不少其它,可參考算法導論或下文我寫的第二篇文章。

完。

July、二零一零年十二月二十九日初稿。三十日凌晨修訂。行文3個小時以上。

----------------

 

今下午畫紅黑樹畫了好幾個鐘頭,貼倆張圖:

  紅黑樹插入的3種狀況:

 

  紅黑樹刪除的4種狀況:

 

ok,僅僅貼倆張,不少其它,參考我寫的關於紅黑樹的第二篇文章:

紅黑樹算法的層層剖析與逐步實現[推薦]
http://blog.csdn.net/v_JULY_v/archive/2010/12/31/6109153.aspx

這篇文章針對算法實現源代碼分十層,層層、逐層剖析,相信,更清晰易懂。

//尤爲文末針對紅黑樹的刪除狀況,層次清晰。

 

             July、二零一零年十二月三十一日、最後更新。

相關文章
相關標籤/搜索