歡迎探討,如有錯誤敬請指正
如需轉載,請注明出處 http://www.cnblogs.com/nullzx/
相關博客:
1. 紅黑樹的定義
2-3-4樹和紅黑樹是完全等價的,由於絕大多數編程語言直接實現2-3-4樹會非常繁瑣,所以一般是通過實現紅黑樹來實現替代2-3-4樹,而紅黑樹本也同樣保證在O(lgn)的時間內完成查找、插入和刪除操作。
紅黑樹是每個節點都帶有顏色屬性的平衡二叉查找樹 ,顏色為紅色或黑色。除了二叉查找樹一般要求以外,對於任何有效的紅黑樹我們增加了如下的額外要求:
(1) 節點是要么紅色或要么是黑色。
(2) 根一定是黑色節點。
(3) 每個葉子結點都帶有兩個空的黑色結點(稱之為NIL節點,它又被稱為黑哨兵)。
(4) 每個紅色節點的兩個子節點都是黑色(或者說從每個葉子到根的所有路徑上不能有兩個連續的紅色節點)。
(5) 從任一節點到它所能到達得葉子節點的所有簡單路徑都包含相同數目的黑色節點。
這些性質保證了根節點到任意葉子節點的路徑長度,最多相差一半(因為路徑上的黑色節點相等,差別只是不能相鄰的紅色節點個數),所以紅黑樹是一個基本平衡的二叉搜索樹,它沒有AVL樹那么絕對平衡,但是同樣的關鍵字組成的紅黑樹相比AVL旋轉操作要少,而且刪除操作也比AVL樹效率更高,實際應用效果也比AVL樹更出眾。當然紅黑樹的具體實現也復雜的多。
紅黑樹的這5個性質中,第3點是比較難理解的,但它卻非常有必要。我們看上面這張圖,如果不使用黑哨兵,它完全滿足紅黑樹性質,根結點5到兩個葉結點1和葉結點9路徑上的黑色結點數都為3個,且沒有連續紅色節點。
但如果加入黑哨兵后,葉結點的個數變為8個黑哨兵,根結點5到這8個葉結點路徑上的黑高度就不一樣了,所以它並不是一棵紅黑樹。NIL節點的存在還可以使得紅黑樹在代碼實現方面得到簡化,在具體實現過程中我們只需要1個NIL節點即可,詳情請關注本博客的下一篇文章,有關紅黑樹代碼的實現。
紅黑樹的所有性質其實都可以從2-3-4樹來理解,這也是理解紅黑樹最好的方式,因為紅黑樹本質就是2-3-4樹。
2. 2-3-4樹和紅黑樹的等價關系
如果一棵樹滿足紅黑樹,把紅結點收縮到其父結點,就變成了2-3-4樹,所有紅色節點都與其父節點構成3或4節點,其它節點為2節點。圖中NIL節點未畫出。
所以紅黑樹的每一類型操作都與2-3-4樹一一對應。黑色節點的個數(或者說位置)對應2-3-4樹中的節點個數(或者說位置),這樣可以很好的理解性質3(從每個葉子到根的所有路徑上不能有兩個連續的紅色節點)和性質5(從任一節點到它所能到達得葉子節點的所有簡單路徑都包含相同數目的黑色節點)以及根節點到任意葉子節點的路徑長度,最多相差一半。
同時我們還需要明白的是,一顆紅黑樹對應唯一形態的2-3-4樹,但是一顆2-3-4樹可以對應多種形態的紅黑樹(主要是3節點可以對應兩種不同的紅黑樹形態),上圖中的2-3-4樹還可以對應下圖中的紅黑樹。我們在后面紅黑樹的刪除操作中會利用這種情況。
3. 紅黑樹中旋轉的定義
因為每種書中對旋轉的定義不一致,所以我們有必要在這里特此說明一下。以某一個節點為軸,它的左子枝順時針旋轉,作為新子樹的根,我們稱之為順時針旋轉(clockwise)或者右旋轉。同理,以某一個節點為軸,它的右子枝逆針旋轉,作為新子樹的根,我們稱之為逆時針旋轉(anticlockwise)或者左旋轉。
4. 紅黑樹的插入操作
(1)如果紅黑樹中已存在待插入的值,那么插入操作失敗,否則一定是在葉子節點進行插入操作,執行步驟2。
(2)當我們插入一個新節點后,我們會把該節點塗紅(塗紅操作,從2-3-4樹的的角度看來,就是向上層節點進位一個key),由於插入操作可能破壞了紅黑樹的平衡性,所以我們需要不斷回溯,進行調整。調整過程就是顏色變換和旋轉操作,而這些操作都可以從2-3-4樹來理解。考慮到回溯的情況,從2-3-4樹的角度,我們可以把X節點看成向上層進位的key。
插入新節點時,我們可能會遇到以下幾種情況
4.1 黑父
插入后直接塗紅,如果父親節點是個黑色,插入結束。
綠色箭頭表示插入的位置,上圖中的虛線表示可以有該節點,也可以沒有該節點,如果有,一定是紅色。當然還有可能在對稱的情況,即在右子支插入,操作方式都是一樣的,由於不涉及到旋轉操作,所以代碼的實現方式也一樣,不在贅述。
這個操作可以從2-3-4樹來理解,相當於2-3-4樹中待插入的葉子節點是個2節點(對應黑父沒有孩子節點)或者3節點(黑父有孩子節點,孩子節點的顏色一定是紅色)。在回溯調整的過程中也會遇到這個情況,回溯時X表示的是下一層向上進位的key,到這個時候就不需要繼續回溯了。
4.2 紅父黑叔
這種情況還有對應的鏡像情況,即P為G的右子支情況
這種情況不會在葉子節點出現,但是會出現在回溯調整的過程中。這種情況相當於2-3-4樹中,容納進位的父節點為3節點,還有空間可以容納key,所以到此就不用繼續回溯了。
4.3 紅父紅叔
這種情況相當於2-3-4樹中,向上進位的父節點為4節點,所以先分裂(對應P和B的顏色變換)然后再插入X,然后繼續回溯,把G看成向更上一層進位的節點(即把G看成新的X)。
這種情況還有對應的鏡像情況,即P為G的右子支情況,但在具體的代碼實現過程中,因為不涉及到旋轉操作,所以不用區分。
5. 紅黑樹的刪除操作
刪除操作可以概括為以下幾個步驟:
(1)查找要刪除的值所在的節點,如果不存在,刪除失敗,否則執行步驟2
(2)如果要刪除的節點不是葉子節點,用要刪除節點的后繼節點替換(只進行數據替換即可,顏色不變,此時也不需要調整結構),然后刪除后繼節點。
那么真正需要刪除的節點有以下幾種可能性
5.1要刪除節點為紅色
5.2要刪除的節點為黑色,且有一個孩子節點,這個孩子節點必然為紅色
5.3要刪除的節點為黑色,孩子節點都NIL
這時,我們刪除這個黑色節點后需要進行調整,在圖中X總表示下一層的節點,一開始X表示NIL節點(回溯過程中X會不斷向上層迭代)。需要調整的情況又可以分為以下幾種。
5.3.1黑兄紅侄
這種情況還有對應的鏡像情況,即P為G的右子支情況
上述兩種情況大致對應2-3-4樹刪除操作中兄弟節點為3節點或4節點,父節點key下移,兄弟節點key上移動,但不完全一致。
5.3.2黑兄黑侄紅父
上述兩種情況都對應2-3-4樹刪除操作中兄弟節點為2節點,父節點至少是個3節點,父節點key下移與兄弟節點合並。
5.3.3黑兄黑侄黑父
對應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對應的紅黑樹形態並不唯一。
上面的兩種紅兄情況,旋轉后對應的還是同一顆2-3-4樹(只是B和P組成的3節點在紅黑樹的兩種不同形態而已),但此時X的兄弟節點和侄子節點發生變化,現在X的兄弟節點就變成了R(第二幅圖中是L),我們正需檢查要R(第二幅圖中是L)的兩個孩子節點的顏色。實際上,此時我們又回到上面討論過的了黑兄的情況。















