算法導論學習-RED-BLACK TREE

1. 紅黑樹(RED-BLACK TREE)引言:html

-------------------------------------算法

紅黑樹(RBT)能夠說是binary-search tree的非嚴格的平衡版本。與之相應的是平衡二叉樹(Balanced Binary Tree)又稱之爲AVL樹(由於是G.M. Adelson-Velsky 和 E.M. Landis在1962年發明的這棵樹)是binary-search tree的嚴格的平衡版本。ide

BST達到最平衡的狀態稱之爲AVL。在AVL樹中任何節點的兩個兒子子樹的高度最大差異爲一,查找、插入和刪除在平均和最壞狀況下都是O(lg n)。但由於增長和刪除節點可能會破壞「平衡狀態」,因此大多數狀況下須要經過屢次樹旋轉來從新平衡這個樹。因此簡單地說,若是你的應用查找次數遠遠多於增刪操做,那麼AVL是最好的,可是若是增刪次數和查找次數不相上下時,RBT由於相比AVL沒有過多的旋轉操做,效率要比AVL高。而且在是實際狀況中,RBT的應用也更爲普遍。至少《intro to algo》這本書上主要講了RBT。函數

2. 紅黑樹幾個基本屬性:spa

------------------------3d

由於RBT是binary-search tree的非嚴格的平衡版本,因此紅黑樹繼承了BST的基本屬性:key值,和基本性質:對於tree中任意節點x,都有x.left.key<x.key<=x.right.key. 此外,BST的葉子節點在RBT不稱之爲葉子節點,RBT的葉子節點爲NIL,因此BST的ROOT節點的父親節點在RBT表示裏再也不爲空,而是NIL或者稱之爲TREE.sentinel. BST中的葉子節點也是同樣,他們也有孩子爲NIL節點。接下來是RBT的獨有屬性:color,即每一個樹節點都有本身的color,要麼要麼指針

而後是RBT的五個基本性質:1)每一個樹節點要麼是紅色要麼是黑色;2)ROOT節點必須是黑色;3)NIL節點爲黑色;4)若是一個節點是紅色,那麼它的孩子節點都是黑色(NIL節點除外),從每一個葉子到根的全部路徑上不能有兩個連續的紅色節點;5)從任一節點到其每一個葉子的全部路徑都包含相同數目的黑色節點。 以下圖所示:code

  

3. 旋轉:htm

--------blog

由於在執行操做或者刪除操做之後,RBT的性質可能會被改變。因此爲了維護RBT的基本性質[2],咱們須要改變一些樹的節點的顏色,同時須要改變樹的結構。下圖展現了樹的旋轉動做:

          

 旋轉動做共有兩種:left 和 right。left-rotation 就是逆時針旋轉,right-rotation是順時針旋轉。以left-roation爲例,如上圖右側所示,

第一步:創建y的左孩子β與x的「親子關係」:β.parent=x AND x.right=β.

第二步:y取代x:(當x不是ROOT節點時) y.parent=x.parent AND (x.parent.left==x)? (y=x.parent.left): (y=x.parent.right).

(當x是ROOT節點時) y=ROOT

第三步:逆轉x,y父子關係: x=y.left AND x.parent=y;

 

 1 LEFT-ROTATE(T, x)
 2 y=x.right
 3 x.right=y.left
 4 if y.left != T.nil
 5         y.left.p=x
 6 y.parent=x.parent
 7 if x.parent==T.nil
 8         T.root=y
 9 else if x==x.parent.left
10         x.parent.left=y
11 else x.parent.left=y
12 y.left=x
13 x.parent=y
View Code

 

 4. 插入:

---------

紅黑樹的插入和BST基本相似。不清楚BST插入算法的能夠參考個人這一篇博客:http://www.cnblogs.com/fu11211129/p/4214047.html

紅黑樹的插入在BST的插入上作了一些微調,這裏把這兩種插入的僞代碼展現作個比較。

 

TREE-INSERT(T, z)//BST插入算法
1 y=NIL
2 x=T.ROOT
3 while(x!=NIL)
4   y=x
5   if(z.key<x.key)
6     x=x.left
7   else x=x.right
8 z.p=y
9 if(y==NIL) T.ROOT=z
10 else if(z.key<y.key) y.left=z
11 else y.right=z
View Code

 

 

RB-TREE-INSERT(T, z)//RBT插入算法
1 y=T.NIL
2 x=T.ROOT
3 while(x!=T.NIL)
4   y=x
5   if(z.key<x.key)
6     x=x.left
7   else x=x.right
8 z.p=y
9 if(y==T.NIL) T.ROOT=z
10 else if(z.key<y.key) y.left=z
11 else y.right=z
12 z.left=T.NIL
13 z.right=T.NIL
14 z.color=RED
17 RB-INSERT-FIXUP(T, z)
View Code

 

對比兩個插入算法,咱們能夠注意到四個不一樣,1)BST中的NIL被替換成了T.NIL,這是由於NIL在紅黑樹體系裏是看作一個節點的。2)RBT-INSERT算法裏14-15行,咱們將T.NIL分別賦值給了z.left和z.right,是爲了保持樹的合理結構。3)在RBT-INSERT算法裏16行將z的顏色設置爲紅色。4)由於給z着色之後可能會致使紅黑樹的基本性質被破壞,因此咱們調用RB-INSERT-FIXUP函數(下面會具體講到)來秀姑RBT樹使之仍能保持它的基本性質。

5. 插入修復(這裏用日本古代武士社會結構作比喻):

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

小日本武士中最大的叫將軍,管着不少大名,大名是有城有地盤,有兵有旗號,有不少家臣爲其服務。家臣又分許多等級,大名的地盤分一部分給家臣,這就是城主。每一個家臣均可以有本身的家臣,只要你地盤的收入俸祿養得起。這個等級制度,很是森嚴,沒有出身保證,就算功勞再大也爬不上去。由於除了將軍,武士必定得效忠於某個主公的,大名也是將軍的家臣。而且這種效忠是繼承的,你的子子孫孫都要效忠主公的後代。

日本和中國狀況不一樣,沒有人敢喊出王候將相,寧有種乎。因此豐臣秀吉能從,最底層的普通武士作起,一步步作到關白(和將軍平級,那時沒設將軍,至關於將軍),成了難以想象的傳奇。當與你的功勞或能力所匹配的待遇,超過了主公所能給予,就可能發生改換門庭,甚至顛覆主公的事情。人們都說日本戰國時代就是一個下克上的時代。

好了,扯得有點遠了,回到正題來。咱們把紅黑樹兩種顏色節點,表明兩個基本的武士類型,黑色表明安分守已對上機忠心耿耿,但同時也庸碌無爲沒能力。紅色表示既有才能,又有野心。

插入操做時,好像一個新的武士出仕,沒有背景,沒有功勳。但他有能力,有抱負(紅色),就像豐臣秀吉那樣。要是跟了個黑色類型的主公,雖然終究會不甘心居人之下,但卻沒條件「下克上」,由於這個主公對大主公(主公的主公)忠心耿耿,兢兢業業,你再有才也英雄無用武之地,只能待時而動了。這種狀況對應着RBT的結構已經穩定。

但要是主公是紅色的(有野心),那新武士就有想入非非了,整天跟大主公打小報告,說他謀反。反正主公忠心有限,把柄不少,只是大主公沒那個洞察力。大主公看到一些莫須有的證據,謀反這事寧枉勿縱。因而新武士舉報有功,主公反倒成了本身的家臣(以下圖第二個狀態)。可是昏庸的大主公很快就要付出代價,本身成了新武士的下一個目標(以下圖第三個狀態)。

            

                (B表示新武士,A表示B的主公)

還有一種狀況就是,主公的有野心的,可是大主公的其餘家臣若是也有野心的話,狀況就不同了,要是其餘家臣也同樣有能力,那就熱鬧了,這一家今後兩虎相爭,不得安寧(此處略去數萬字)。大主公能力平庸,控制不住,最終釀成大亂,通過一番血雨腥風,大主公家出現了一位雄才偉略的家主,平定了內亂,原來兩家的強勢家主所有被消滅,家主換成了忠心可靠(變黑)的人。而大主公家的新家主,野心開始膨漲了(變紅)

 

下面走一遍完整的流程:

好了從a)圖開始,新武士編號爲4(這裏我就不標紅圈了,陰影的就表明紅色)在家臣5的手下作事。家臣5不肯意屈居人下,而4發現了這一點,4想攛掇5去篡權。但不幸的是,一樣是7的家臣,家臣8,也是野心勃勃(紅色)。因此在大名7的統治下,出現了混亂的局面,羣雄四起。。。最終大名家族又出現了一名新的大名7,平定了內亂,將家臣5和8換成了對本身忠心的家臣。並且與此同時,新的大名7也是野心膨脹(變紅)。(在途中對應的是狀態1通過case1到達狀態2)

新的大名7野心勃勃,並且他的主公2也是野心不小,因此大名7只能戰而玩陰的了,大名7向大主公11說主公2的壞話。大主公也是二貨(黑色),聽風就是雨,大名7舉報有功,這樣一來,主公2反倒成了大名7的下屬了。可是很快的,這位二貨打主攻11也要自食惡果了,大名7直接佔了他的位置。

6. 移植:

--------

由於移植操做是刪除操做的一個基本動做,因此這裏先作個簡要說明。RBT的移植算法基本和BST的一致,你們能夠參照博

RB-TRANPLANT(T, u, v)
1 if (u.parent==NIL) T.ROOT=v
2 else if(u==u.parent;.left) u.parent.left=v
3 else u.parent.right=v
4 v.parent=u.parent
View Code

客:http://www.cnblogs.com/fu11211129/p/4214047.html

你們能夠發現只有第四行不同,緣由很簡單,RBT把NIL看作一個節點了。

7. 刪除:

--------

刪除操做是比較麻煩的一部份內容,但相似的,和BST刪除操做也很類似,http://www.cnblogs.com/fu11211129/p/4214047.html

下面貼出RBT的刪除操做的僞代碼:

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 ≠ 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)
View Code

由於相比BST刪除算法,就是加入一些節點顏色的處理機制,因此這裏再也不贅述。你們理解了BST的刪除後,RBT也就差很少了。

8. 刪除修復(尚未想到合適的比喻,想到了會更新這一部分):

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

仍是先貼上僞代碼吧,而後結合代碼作個分析。

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
View Code

前面,我已經說了,由於插入、或刪除結點後,可能會違背、或破壞紅黑樹的原有的性質,因此爲了使插入、或刪除結點後的樹依然維持爲一棵新的紅黑樹,那就要作倆方面的工做:一、部分結點顏色,從新着色 二、調整部分指針的指向,即左旋、右旋。而下面全部的文字,則是針對紅黑樹刪除結點後,所作的修復紅黑樹性質的工做。

狀況1:當前節點的兄弟節點是紅色;解法,在當前節點的父節點上進行左旋,結束。此時紅黑樹性質所有恢復。


狀況2:當前節點的兄弟節點是黑色而且兄弟節點的孩子節點也都是黑色 解法:直接把兄弟節點變成紅色就好了。

狀況3:當前節點的兄弟節點是黑色,且兄弟節點的左孩子爲紅色,右孩子爲黑色。解法:在兄弟節點的左孩子上右旋,而且互換父親左孩子的顏色。

狀況3:當前節點的兄弟節點是黑色,且兄弟節點的兩個孩子都爲紅色。解法: 在父親節點上左旋,而且互換父親右孩子顏色。

(日本武士版解釋:在介紹插入的時候,咱們「插入故事」的「主人翁」是一個剛出道的武士,雄姿英發,羽扇綸巾。。。,在這裏咱們「刪除故事」的主人翁是一個「要退役」的武士x,可是秉承武士「猥瑣的」特色,x下崗以前,總要把格局教的混亂不堪才行。可是由於x要「退役」了,因此他本身是沒有能力的(黑色)。因此他把目光轉移到了他的兄弟上,但這也要看他的兄弟w是個什麼貨色

若是他胸無大志,那麼x就撩起兄弟w的野心(變紅)(對應case2)。

若是他的兄弟w是有野心的(紅色),x也就不用攛掇了,可是兵法有云,攘外必先安內(我也不知道是否是兵法上的,姑且這麼說吧),若是w的兩個家臣都安分守己,那麼好,w就能夠放心去搶班奪權了(對應case1),w成功以後志得意滿,生活墮落(變黑),而被w強權的曾經上級B開始臥薪嚐膽了(變紅)(對應case1)。

若是他的兄弟w胸無大志,可是他的其中一個家臣野心不小,那麼x就轉而開始攛掇w的家臣犯上做亂(對應case3)。

若是他的兄弟w胸無大志,並且悲催的是,他的家臣沒有一個真正沉服於他的。那麼x心想我不用攢多了,讓他們內鬥吧,最後D家族出了一位新的w,先是成功篡權,而後將本身的手下換成對本身中心的人(黑色

相關文章
相關標籤/搜索