從2-3-4樹到紅黑樹(中)

歡迎探討,若有錯誤敬請指正html

如需轉載,請註明出處   http://www.cnblogs.com/nullzx/ 編程

相關博客:編程語言

從2-3-4樹到紅黑樹(上)spa

從2-3-4樹到紅黑樹(下)htm

1. 紅黑樹的定義

2-3-4樹和紅黑樹是徹底等價的,因爲絕大多數編程語言直接實現2-3-4樹會很是繁瑣,因此通常是經過實現紅黑樹來實現替代2-3-4樹,而紅黑樹本也一樣保證在O(lgn)的時間內完成查找、插入和刪除操做。blog

紅黑樹是每一個節點都帶有顏色屬性的平衡二叉查找樹 ,顏色爲紅色或黑色。除了二叉查找樹通常要求之外,對於任何有效的紅黑樹咱們增長了以下的額外要求:get

(1) 節點是要麼紅色或要麼是黑色。博客

(2) 根必定是黑色節點。it

(3) 每一個葉子結點都帶有兩個空的黑色結點(稱之爲NIL節點,它又被稱爲黑哨兵)。效率

(4) 每一個紅色節點的兩個子節點都是黑色(或者說從每一個葉子到根的全部路徑上不能有兩個連續的紅色節點)。

(5) 從任一節點到它所能到達得葉子節點的全部簡單路徑都包含相同數目的黑色節點。

這些性質保證了根節點到任意葉子節點的路徑長度,最多相差一半(由於路徑上的黑色節點相等,差異只是不能相鄰的紅色節點個數),因此紅黑樹是一個基本平衡的二叉搜索樹,它沒有AVL樹那麼絕對平衡,可是一樣的關鍵字組成的紅黑樹相比AVL旋轉操做要少,並且刪除操做也比AVL樹效率更高,實際應用效果也比AVL樹更出衆。固然紅黑樹的具體實現也複雜的多。

image_thumb55

紅黑樹的這5個性質中,第3點是比較難理解的,但它卻很是有必要。咱們看上面這張圖,若是不使用黑哨兵,它徹底知足紅黑樹性質,根結點5到兩個葉結點1和葉結點9路徑上的黑色結點數都爲3個,且沒有連續紅色節點。

但若是加入黑哨兵後,葉結點的個數變爲8個黑哨兵,根結點5到這8個葉結點路徑上的黑高度就不同了,因此它並非一棵紅黑樹。NIL節點的存在還可使得紅黑樹在代碼實現方面獲得簡化,在具體實現過程當中咱們只須要1個NIL節點便可,詳情請關注本博客的下一篇文章,有關紅黑樹代碼的實現。

 

image_thumb52

紅黑樹的全部性質其實均可以從2-3-4樹來理解,這也是理解紅黑樹最好的方式,由於紅黑樹本質就是2-3-4樹。

2. 2-3-4樹和紅黑樹的等價關係

若是一棵樹知足紅黑樹,把紅結點收縮到其父結點,就變成了2-3-4樹,全部紅色節點都與其父節點構成3或4節點,其它節點爲2節點。圖中NIL節點未畫出。

image_thumb53

因此紅黑樹的每一類型操做都與2-3-4樹一一對應。黑色節點的個數(或者說位置)對應2-3-4樹中的節點個數(或者說位置),這樣能夠很好的理解性質3(從每一個葉子到根的全部路徑上不能有兩個連續的紅色節點)和性質5(從任一節點到它所能到達得葉子節點的全部簡單路徑都包含相同數目的黑色節點)以及根節點到任意葉子節點的路徑長度,最多相差一半

同時咱們還須要明白的是,一顆紅黑樹對應惟一形態的2-3-4樹,可是一顆2-3-4樹能夠對應多種形態的紅黑樹(主要是3節點能夠對應兩種不一樣的紅黑樹形態),上圖中的2-3-4樹還能夠對應下圖中的紅黑樹。咱們在後面紅黑樹的刪除操做中會利用這種狀況。

image_thumb54

3. 紅黑樹中旋轉的定義

由於每種書中對旋轉的定義不一致,因此咱們有必要在這裏特此說明一下。以某一個節點爲軸,它的左子枝順時針旋轉,做爲新子樹的根,咱們稱之爲順時針旋轉(clockwise)或者右旋轉。同理,以某一個節點爲軸,它的右子枝逆針旋轉,做爲新子樹的根,咱們稱之爲逆時針旋轉(anticlockwise)或者左旋轉

4. 紅黑樹的插入操做

(1)若是紅黑樹中已存在待插入的值,那麼插入操做失敗,不然必定是在葉子節點進行插入操做,執行步驟2。

(2)當咱們插入一個新節點後,咱們會把該節點塗紅(塗紅操做,從2-3-4樹的的角度看來,就是向上層節點進位一個key),因爲插入操做可能破壞了紅黑樹的平衡性,因此咱們須要不斷回溯,進行調整。調整過程就是顏色變換和旋轉操做,而這些操做均可以從2-3-4樹來理解。考慮到回溯的狀況,從2-3-4樹的角度,咱們能夠把X節點當作向上層進位的key。

插入新節點時,咱們可能會遇到如下幾種狀況

 

4.1 黑父

image_thumb51

插入後直接塗紅,若是父親節點是個黑色,插入結束。

綠色箭頭表示插入的位置,上圖中的虛線表示能夠有該節點,也能夠沒有該節點,若是有,必定是紅色。固然還有可能在對稱的狀況,即在右子支插入,操做方式都是同樣的,因爲不涉及到旋轉操做,因此代碼的實現方式也同樣,不在贅述。

這個操做能夠從2-3-4樹來理解,至關於2-3-4樹中待插入的葉子節點是個2節點(對應黑父沒有孩子節點)或者3節點(黑父有孩子節點,孩子節點的顏色必定是紅色)。在回溯調整的過程當中也會遇到這個狀況,回溯時X表示的是下一層向上進位的key,到這個時候就不須要繼續回溯了。

4.2 紅父黑叔

image_thumb18

 

這種狀況還有對應的鏡像狀況,即P爲G的右子支狀況

image_thumb21

這種狀況不會在葉子節點出現,可是會出如今回溯調整的過程當中。這種狀況至關於2-3-4樹中,容納進位的父節點爲3節點,還有空間能夠容納key,因此到此就不用繼續回溯了。

4.3 紅父紅叔

image_thumb24

這種狀況至關於2-3-4樹中,向上進位的父節點爲4節點,因此先分裂(對應P和B的顏色變換)而後再插入X,而後繼續回溯,把G當作向更上一層進位的節點(即把G當作新的X)。

這種狀況還有對應的鏡像狀況,即P爲G的右子支狀況,但在具體的代碼實現過程當中,由於不涉及到旋轉操做,因此不用區分。

5. 紅黑樹的刪除操做

刪除操做能夠歸納爲如下幾個步驟:

(1)查找要刪除的值所在的節點,若是不存在,刪除失敗,不然執行步驟2

(2)若是要刪除的節點不是葉子節點,用要刪除節點的後繼節點替換(只進行數據替換便可,顏色不變,此時也不須要調整結構),而後刪除後繼節點。

那麼真正須要刪除的節點有如下幾種可能性

5.1要刪除節點爲紅色

image_thumb35

5.2要刪除的節點爲黑色,且有一個孩子節點,這個孩子節點必然爲紅色

image_thumb34

5.3要刪除的節點爲黑色,孩子節點都NIL

這時,咱們刪除這個黑色節點後須要進行調整,在圖中X總表示下一層的節點,一開始X表示NIL節點(回溯過程當中X會不斷向上層迭代)。須要調整的狀況又能夠分爲如下幾種。

 

5.3.1黑兄紅侄

image_thumb33

這種狀況還有對應的鏡像狀況,即P爲G的右子支狀況

image_thumb38

上述兩種狀況大體對應2-3-4樹刪除操做中兄弟節點爲3節點或4節點,父節點key下移,兄弟節點key上移動,但不徹底一致。

 

5.3.2黑兄黑侄紅父

image_thumb42

上述兩種狀況都對應2-3-4樹刪除操做中兄弟節點爲2節點,父節點至少是個3節點,父節點key下移與兄弟節點合併。

 

5.3.3黑兄黑侄黑父

image_thumb45

對應2-3-4樹刪除操做中兄弟節點爲2節點,父親節點也爲2節點,父節點key下移與兄弟節點合併,已父節點當作新的X,繼續回溯。

 

5.3.4紅兄(黑侄黑父)

按照2-3-4刪除操做的原理,咱們這裏應該檢測黑侄R(第二幅圖中是L)的兩個孩子節點是否存在紅色節點(對應2-3-4樹,是不是2節點),但這樣作使用的局部變量也會增多,代碼實現起來也會變得很是複雜。咱們這裏作了一個技巧性處理,以P爲軸進行旋轉,它原理就是第2部分2-3-4樹和紅黑樹的等價關係中講到的:一顆2-3-4對應的紅黑樹形態並不惟一。

image_thumb48

上面的兩種紅兄狀況,旋轉後對應的仍是同一顆2-3-4樹(只是B和P組成的3節點在紅黑樹的兩種不一樣形態而已),但此時X的兄弟節點和侄子節點發生變化,如今X的兄弟節點就變成了R(第二幅圖中是L),咱們正需檢查要R(第二幅圖中是L)的兩個孩子節點的顏色。實際上,此時咱們又回到上面討論過的了黑兄的狀況。

相關文章
相關標籤/搜索