紅黑樹除了符合二叉搜索樹的基本規則外,還添加了如下特性:算法
紅黑樹的相對平衡數據結構
前面5條規則的約束確保瞭如下紅黑樹的關鍵特性:ide
爲何能夠作到最長路徑不超過最短路徑的兩倍呢?遞歸
插入一個新節點時,有可能樹再也不平衡,能夠經過三種方式的變換使樹保持平衡:ip
爲了從新符合紅黑樹的規則,須要把紅色節點變爲黑色,或者把黑色節點變爲紅色;v8
插入的新節點一般都是紅色節點:get
當插入的節點爲紅色的時候,大多數狀況不違反紅黑樹的任何規則;效率
紅色節點雖然可能致使紅紅相連的狀況,可是這種狀況能夠經過顏色調換和旋轉來調整;原理
以節點X爲根逆時針旋轉二叉搜索樹,使得父節點原來的位置被本身的右子節點替代,左子節點的位置被父節點替代;數據結構與算法
詳解:
如上圖所示,左旋轉以後:
除此以外,二叉搜索樹左旋轉以後仍爲二叉搜索樹:
以節點X爲根順時針旋轉二叉搜索樹,使得父節點原來的位置被本身的左子節點替代,右子節點的位置被父節點替代;
詳解:
如上圖所示,右旋轉以後:
除此以外,二叉搜索樹右旋轉以後仍爲二叉搜索樹:
首先須要明確,在保證知足紅黑樹5條規則的狀況下,新插入的節點必然是紅色節點。
爲了方便說明,規定如下四個節點:新插入節點爲N(Node),N的父節點爲P(Parent),P的兄弟節點爲U(Uncle),U的父節點爲G(Grandpa),以下圖所示:
當插入的新節點N位於樹的根上時,沒有父節點。
這種狀況下,只須要將紅色節點變爲黑色節點便可知足規則2 。
新界點N的父節點P爲黑色節點,此時不須要任何變化。
此時既知足規則4也知足規則5。儘管新節點是紅色的,可是新節點N有兩個黑色節點NIL,因此通向它的路徑上黑色節點的個數依然相等,所以知足規則5 。
節點P爲紅色,節點U也爲紅色,此時節點G必爲黑色,即父紅叔紅祖黑。
在這種狀況下須要:
即變爲父黑叔黑祖紅,以下圖所示:
可能出現的問題:
節點P是紅色節點,節點U是黑色節點,而且節點N爲節點P的左子節點,此時節點G必定是黑色節點,即父紅叔黑祖黑。
在這種狀況下須要:
節點P是紅色節點,節點U是黑色節點,而且節點N爲節點P的右子節點,此時節點G必定是黑色節點,即父紅叔黑祖黑。
在這種狀況下須要:
接着能夠按照狀況4進行處理:
先變色:將N1節點的父節點P1變爲黑色,將祖父節點G變爲紅色;
最後將節點N1和P1變換回來,完成節點N的插入,如圖 f 所示;
在二叉樹中依次插入節點:10,9,8,7,6,5,4,3,2,1 。
若是直接採用普通的二叉搜索樹,節點所有插入後是這樣的:
是一個嚴重的不平衡樹,至關於一個鏈表,不能體現出二叉搜索樹的高效率。而按照紅黑樹的五條規則插入節點就能最大程度保證搜索二叉樹是一棵平衡樹。如下爲過程詳解:爲了方便解釋省略了部分成黑樹的葉子節點(NIL)
符合狀況1:
符合狀況2:
快速判斷屬於狀況3仍是狀況4的方法:
重新插入的節點N出發,按圖示箭頭通過的四個節點,若爲紅紅黑紅3個紅色節點則爲狀況3,若爲紅紅黑黑兩個紅色節點則爲狀況4;
符合狀況4:
符合狀況3:
符合狀況4:
符合狀況3:
符合狀況4:
第一次變換:符合狀況3:
變換以後發現5和7爲相連的兩個紅色節點,因而把以5爲根的整個子樹當作一個新插入的節點N1,再進行第二次變換。
第二次變換:符合狀況4:
最後復原N1獲得變換後的紅黑樹:
符合狀況4:
第一次變換:符合狀況3:
變換以後發現3和5爲相連的兩個紅色節點,因而把以3爲根的整個子樹當作一個新插入的節點N1,再進行第二次變換。
第二次變換:符合狀況3:
變換以後發現根節點7爲紅色不符合規則2,因此把以7爲根節點的紅黑樹當作一個新插入的節點N2,再進行第三次變換。
第三次變換:符合狀況1:
由此,完成了1~10節點的插入,雖然沒有遇到狀況5,不過狀況5通過左旋轉的操做即可轉換爲狀況4,原理同樣。以下圖所示,將這棵紅黑樹的葉子節點NIL補全以後,經檢驗知足紅黑樹的五條規則,而且基本屬於平衡樹,效率較高。
紅黑樹的刪除操做結合了複雜的二叉樹的刪除操做和複雜的紅黑樹的插入規則,總體來講難度很是大,篇幅較長,這裏暫不進行探討。
參考資料:JavaScript數據結構與算法