紅黑樹(平衡操作詳解)
阿新 • • 發佈:2019-01-25
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資料結構和演算法(第二版)
二叉樹如果插入的數值是有序時,二叉樹就是非平衡的,基本跟連結串列類似了(時間複雜度O(N))
針對這種情況,就產生了紅黑樹,這種樹在插入的過程中,會通過一系列的方式來保持樹的平衡,使其時間複雜度一直維持在O(logN)
2.紅黑樹規則 * 每一個節點不是黑色就是紅色 * 根節點總是黑色的
* 如果節點是紅色的,則它的子節點必須是黑色的(反之則不一定)
* 從根到葉節點的每條路徑,包含的黑色節點數目必須相同
3.紅黑樹修正違規操作簡介 紅黑樹之所以能夠保持平衡,是因為嚴格遵守了上述規則
在插入的過程中,如果某節點違反了以上規則,則需要進行修正,修正的方式包括:改變顏色、旋轉
1)術語
為了平衡一棵樹,需要對某些節點進行重新排列,將一些節點上升,將一些節點下降,以此來幫助樹平衡。
切記:在樹平衡操作的過程中不能破壞二叉樹的特點(一個節點的左子節點的關鍵字值小於這個節點,右子節點的關鍵字值大於或等於這個父節點)
旋轉之前先了解一些基本概念:
* 外側子孫12在18的左側,18在25的左側,它們的相對父節點位置相同,則稱新插入的節點12為外側子孫節點38在35的右側,35在25的右側,它們的相對父節點位置相同,則稱新插入的節點38為外側子孫節點
* 內側子孫22在18的右側,18在25的左側,它們的相對父節點位置不同,則稱新插入的節點22為內側子孫節點
可以看到,在插入新節點之前的樹都是平衡的,但是插入新節點之後就會違反規則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資料結構和演算法(第二版)