1. 程式人生 > >紅黑樹(平衡操作詳解)

紅黑樹(平衡操作詳解)

1.紅黑樹    紅黑樹本身也是一種二叉樹,只不過是一種比較特殊的二叉樹
    二叉樹如果插入的數值是有序時,二叉樹就是非平衡的,基本跟連結串列類似了(時間複雜度O(N))
    針對這種情況,就產生了紅黑樹,這種樹在插入的過程中,會通過一系列的方式來保持樹的平衡,使其時間複雜度一直維持在O(logN)
2.紅黑樹規則    * 每一個節點不是黑色就是紅色    * 根節點總是黑色的
    * 如果節點是紅色的,則它的子節點必須是黑色的(反之則不一定)
    * 從根到葉節點的每條路徑,包含的黑色節點數目必須相同
3.紅黑樹修正違規操作簡介    紅黑樹之所以能夠保持平衡,是因為嚴格遵守了上述規則
    在插入的過程中,如果某節點違反了以上規則,則需要進行修正,修正的方式包括:改變顏色、旋轉
    1)術語

        為了平衡一棵樹,需要對某些節點進行重新排列,將一些節點上升,將一些節點下降,以此來幫助樹平衡。
        切記:在樹平衡操作的過程中不能破壞二叉樹的特點(一個節點的左子節點的關鍵字值小於這個節點,右子節點的關鍵字值大於或等於這個父節點
        旋轉之前先了解一些基本概念:
       * 外側子孫12在18的左側,18在25的左側,它們的相對父節點位置相同,則稱新插入的節點12為外側子孫節點38在35的右側,35在25的右側,它們的相對父節點位置相同,則稱新插入的節點38為外側子孫節點
       * 內側子孫22在18的右側,18在25的左側,它們的相對父節點位置不同,則稱新插入的節點22為內側子孫節點
30在35的左側,35在25的右側,它們的相對父節點位置不同,則稱新插入的節點30為內側子孫節點

        可以看到,在插入新節點之前的樹都是平衡的,但是插入新節點之後就會違反規則3,故需要對這些樹進行修正(看到子節點和父節點都是紅色的,就要想到使用旋轉來保持樹的平衡)
        * 右旋轉
當以35為頂端元素進行右旋轉時,需要注意:該頂端元素必須有一個左子元素
右旋結果如下:35下移,30上移到35的位置,20位置不變,依舊是30的左子元素        * 左旋轉
當以30為頂端元素進行左旋轉時,需要注意:該頂端元素必須有一個右子節點左旋結果如下:30下移到左側,35上移到30的位置,45位置不變,依舊是35的右子節點
    2)顏色變換

        場景:當在插入的過程中遇到一個黑色節點下有兩個紅色節點,則需要進行顏色變換
        示例:        當前場景下,是符合紅黑樹規則的,如果此時再插入一個節點,按照規則3,則新節點只能是黑色的,但是這樣就會違反規則4,所以對現有節點進行變色        * 把25、75兩個子節點變色為黑色        * 再新插入節點為紅色即可
操作完成之後的樹為  3)外側子孫的旋轉平衡術針對上述這種情況,找到新插入節點12的祖父節點25,然後以25為頂端,進行右旋轉

上述這種情況,找到新插入節點38的祖父節點25,以25為頂端,進行左旋轉
    4)內側子孫的旋轉平衡術上述這種情況,找到新插入節點22的父節點18,然後以18位頂端,進行左旋轉,旋轉後結果如下

然後以22的父節點25進行右旋轉,旋轉結果如下        再修改22和18、25節點的顏色,即保持樹的正確
    總結:外側子孫和內側子孫的平衡都是需要進行旋轉,不同的是外側子孫只需要進行一次旋轉即可,而內側子孫則需要進行兩次旋轉,第一次旋轉後變成外側子孫的模式,再根據外側子孫的方式來進行平衡即可
3.插入新節點    紅黑樹插入新節點的過程中,會遇到違背紅黑樹規則的情況,為了保持樹的平衡,則需要使用以上的幾種方式來保持樹平衡
    下面介紹下以下幾種插入新節點過程中遇到的問題及其解決方案:
    1)在下行過程中發現黑色節點下有兩個紅色子節點
        為什麼這種情況是會違背紅黑樹規則呢?因為根據規則3,紅色節點下的子節點必須為黑色節點,那麼插入黑色子節點後就會違背規則4,所以碰到這種情況,需要對這三個節點進行顏色變換當再插入12節點時,就會與18節點產生顏色衝突,所以需要對18 25 30三個節點進行顏色變換,變換成如下,再插入12節點即可
    2)插入節點後發生顏色衝突
        接著上個樹來繼續新增節點6
發現6節點和12節點都是紅色,違背規則3,則根據上述外側子孫節點處理方案對6的祖父節點18進行右轉此時12和25節點都是紅色,同樣違背規則3,對12的祖父節點50節點進行右轉

再對上述節點顏色錯誤的進行顏色變換,25、12、6節點都變成黑色,即變成一顆複合規則的紅黑樹



    3)插入過程中發生顏色衝突
以上節點屬於平衡狀態,此時如果再插入節點3,則需要對12、6、18節點進行顏色變換操作
此時12和25節點又發生了顏色衝突,則需要找到12節點的祖父節點50,然後以50節點進行右旋轉

再改變25和12的顏色為黑色,以符合規則2和4

此時已經平衡,再插入節點3即可,結果如下

    總結:針對於紅紅衝突,需要找到合適的祖父節點,然後進行旋轉,再進行節點顏色變換,則就可以保持樹的平衡
    至於程式碼實現,可以參考TreeMap參考:Java資料結構和演算法(第二版)