紅黑樹的介紹和實現

一、紅黑樹

紅黑樹(Red-Black Tree)是二叉搜索樹(Binary Search Tree) 的一種。二叉搜索樹在最壞的情況下可能會變成一個鏈表(當所有節點按從小到大的順序依次插入後)。這種低效產生的原因是樹沒有維持一定的平衡性,要提高搜 索效率,就要想辦法來維持樹左邊的平衡,也就是要盡時降低樹的高度,可行的做法就是用一些策略在每次修改樹的內容之後都調整樹的結構,使之滿足一定的平衡 條件。其中一種滿足一定平衡條件而且目前應用廣泛的是紅黑樹。它可以在每一次插入或刪除節點之後都會花O(log N)的時間來對樹的結構作修改,以保持樹的平衡。而紅黑樹的查找方法與二叉搜索樹完全一樣,也能夠在O(log N)時間上完成。而紅黑樹的插入和刪除節點的的方法只是在原二叉搜索樹搜索和刪除算法之後經過一定的過程來維持紅黑樹的性質不變。

紅黑樹的每個節點上的屬性除了有一個key、3個指針:parent、left、right以外,還多了一個屬性:color。它只能是兩種顏色:紅或黑,當然也可以再加一些以key來索引的數據。

而紅黑樹除了具有二叉搜索樹的所有性質之外,還具有以下5點性質:

1.每個節點是黑色的或是紅色的。

2.根節點是黑色的。

3.空節點是黑色的(紅黑樹中,根節點的parent以及所有葉節點left、right都不指向NULL,而是指向一個定義好的空節點,這樣可以保持算法的一致性,簡化算法)。

4.紅色節點的父、左子、右子節點都是黑色。

5.在任何一棵子樹中,每一條從根節點向下走到空節點的路徑上包含的黑色節點數量都相同。

如下圖就是一棵紅黑樹:


小記:

1. 在一棵紅黑樹中null節點是很多的,如果每個null節點都用一個真的節點的話那就太浪費空間了,我們可以對所有的null節點都使用同一個節點,這樣可以簡化算法又能節約空間。

2. 由於紅黑樹的結構比較複雜,代碼的書寫一定要常規,比如一般null的left,right和parent都指向樹的根節點,但是一般不應該用null節點來索引根節點或是做相應的判斷,因爲在一些地方我們爲了保持算法的一致性,可能改變null節點的left,right,parent的指向。

3. 這裏的紅黑樹實現並不是真的想拿來應用,而是拿來練習,因此在代碼的實現上沒有過份的考慮效率而影響可讀性,因爲紅黑樹結構複雜,裏面很多部分的代碼並不能隨意寫出而無錯誤,直接寫出易引入很多細小的bug,因此很多地方要用數學方法來嚴格證明算法的正確性。


二、前備知識

   1.樹的旋轉

      a)左旋 

 

                    (pivot,a,b,c,y逆時針旋轉)   

 b)右旋

 

                                  (pivot,a,c,b,y順時針旋轉)

對於樹的旋轉,能保持不變的只有原樹的搜索性質,而原樹的紅黑性質則不能保持,在紅黑樹的數據插入和刪除後可利用旋轉和顏色重塗來恢復樹的紅黑性質。對於有 些材料中有對雙旋的描述,其實雙旋只是單旋的兩次應用,並無新的內容,因此這裏就不再介紹了,而且左右旋也是相互對稱的,只要理解其中一種旋轉就可以了。


2.前趨和後繼

   由於在搜索樹中總是可能操作到它的中序前趨和後繼,因些在樹中找到它的前趨和後繼也是比較重要的。

   在二叉搜索樹中,一個節點的前趨只能出現在兩個地方

1)節點左子樹的最右節點,如果節點左子樹爲則爲情況2

2)節點左子樹爲空,節點前趨只能是它的雙親節點中第一個爲右雙親的節點,下面爲此種情況的一個示例,B爲F中序遍歷的前趨。

 

直接後繼的情況與此對稱,不再介紹。 

 

三、樹的修改操作

   1.插入操作

   我們總是插入紅色的節點,因爲這樣就可以在插入過程中儘量避免產生對樹的調整,我們新插入一個節點後可能使原樹的哪些性質改變呢。由於我們是按二叉樹的方式插入,因此原樹的搜索性質不會改變。如果插入的節點是根節點,性質2會被破壞,如果插入的節點的父節點是紅色,則會破壞性質4,因此總的來說,插入一個紅色節點只會破壞到性質2或是性質4, 我們的恢復樹性質的策略很簡單,其一就是保持一定的性質不變,之後把出現違背紅黑樹性質地方向上移,如果能移到根節點,那麼很容易就可以通過直接修改根節 點來恢復紅黑樹應滿足的性質。其二就是窮舉所有的可能性,之後把能歸於同一類方法處理的歸爲同一類,不能直接處理的化歸到其它可以直接處理的情況,能直接 處理的就直接處理。

下面看看一共有幾種情況,

情況1:插入的是根節點(原樹是空樹)

此情況只會違反性質2。

解法:直接把此節點塗爲黑色


情況2:插入的節點的的父節點是黑色

此時不會違反性質2也不會違反性質4,紅黑樹沒有被破壞。

解法:什麼都不做


情況3:當前節點的父節點是紅色且祖父節點的另一個子節點(叔叔節點)是紅色(此時父節點的父節點一定存在,否則插入前就已不是紅黑樹,此時又分爲父節點是祖父節點的左子或者右子,對於對稱性,只要解開一個方向就可以了,我們只考慮父節點爲祖父左子的情況)。此時還可分爲當前節點是其父節點的左子還是右子,但是這兩種情況的處理方式是一樣的,我們將其歸爲同一類。

解法:將當前節點的父節點和叔叔節點塗黑,祖父結點塗紅,把當前結點指向祖父節點,從新的當前節點重新開始算法。


下面是算法導論一書中的圖,稍做修改(N代表當前節點,P代表父節點,G代表祖父節點,U代表叔叔節點,以下各圖如果相同字母則代表同一意思,不再詳述)。

變換前



變換後


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

解法:當前節點的父節點做爲新的當前節點,以新當前節點爲支點左旋。

如下圖所示

變換前

 

 

變換後


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

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

如下圖所示

變換前



變換後



在上面的插入算法中,所有遞歸都是尾遞歸,可以改寫爲循環,其中以當前節點的父節點是否爲紅色是十分方便的。


2.刪除操作

   我 們刪除的節點的方法與常規二叉搜索樹中刪除節點的方法是一樣的,如果被刪除的節點不是有雙非空子女,則直接刪除這個節點,用它的唯一子節點頂替它的位置, 如果它的子節點分是空節點,那就用空節點頂替它的位置,如果它的雙子全爲非空,我們就把它的直接後繼節點內容複製到它的位置,之後以同樣的方式刪除它的後 繼節點,它的後繼節點不可能是雙子非空,因此此傳遞過程最多隻進行一次。在冊除節點後,原紅黑樹的性質可能被改變,如果刪除的是紅色節點,那麼原紅黑樹的 性質依舊保持,此時不用做修正操作,如果刪除的節點是黑色節點,原紅黑樹的性質可能會被改變,我們要對其做修正操作。那麼哪些樹的性質會發生變化呢,如果 刪除節點不是樹唯一節點,那麼刪除節點的那一個支的到各葉節點的黑色節點數會發生變化,此時性質5被破壞。如果被刪節點的唯物主唯一非空子節點是紅色,而被刪節點的父節點也是紅色,那麼性質4被破壞。如果被刪節點是根節點,而它的唯一非空子節點是紅色,則刪除後新根節點將變成紅色,違背性質2。 現在情況看起來有些複雜,這裏面我們用一個分析技巧,這引技巧是從《算法導論》一書中學來的。我們從被刪節點後來頂替它的那個節點開始調整,並認爲它有額 外的一重黑色。這裏額外一重黑色是什麼意思呢,我們不是把紅黑樹的節點加上除紅與黑的另一種顏色,這裏只是一種假設,我們認爲我們當前指向它,因此空有額 外一種黑色,可以認爲它的黑色是從它的父節點被刪除後繼承給它的,它現在可以容納兩種顏色,如果它原來是紅色,那麼現在是紅+黑,如果原來是黑色,那麼它現在的顏色是黑+黑。有了這重額外的黑色,原紅黑樹性質5就能保持不變。現在只要花時是恢復其它性質就可以了,做法還是儘量向根移動和窮舉所有可能性。

情況1:當前節點是紅+黑色

   解法,直接把當前節點染成黑色,結束。

此時紅黑樹性質全部恢復。

情況2:當前節點是黑+黑且是根節點

   解法:什麼都不做,結束

情況3:當前節點是黑+黑且兄弟節點爲紅色(此時父節點和兄弟節點的子節點分爲黑)。

   解法:把父節點染成紅色,把兄弟結點染成黑色,之後重新進入算法(我們只討論當前節點是其父節點左孩子時的情況)。此變換後原紅黑樹性質5不變,而把問題轉化爲兄弟節點爲黑色的情況。

變換前

 


變換後

 


 情況4:當前節點是黑加黑且兄弟是黑色且兄弟節點的兩個子節點全爲黑色

   解法:把當前節點和兄弟節點中抽取一重黑色追加到父節點上,把父節點當成新的當前節點,重新進入算法。(此變換後性質5不變)

變換前

 


變換後


 

情況5:當前節點顏色是黑+黑,兄弟節點是黑色,兄弟的左子是紅色,右子是黑色。

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

變換前



 變換後


 

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

解法:把兄弟節點染成當前節點父節點的顏色,把當前節點父節點染成黑色,兄弟節點右子染成黑色,之後以當前節點的父節點爲支點進行左旋,此時算法結束,紅黑樹所有性質調整正確。

 

 變換後


 

下面的地址包含了一個插入序列和一個刪除除序列中紅黑樹的狀態,可以通過觀查,以加深理解。

http://saturnman.blog.163.com/blog/static/557611201097221570/

下面是相關代碼,僅供參考。

http://saturnman.blog.163.com/blog/static/55761120109872943826/

 

Ref:< xmlnamespace prefix ="o" ns ="urn:schemas-microsoft-com:office:office" />

[1]Introduction to Algorithms, Second Edition

http://www.amazon.com/Introduction-Algorithms-Second-Thomas-Cormen/dp/0262032937

 

[2]Wikipedia Red Black Tree entry

http://en.wikipedia.org/wiki/Red_black_tree



發佈了28 篇原創文章 · 獲贊 26 · 訪問量 32萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章