<紅黑樹並無咱們想象的那麼難> 上、下兩篇已經完成, 但願能幫助到你們.html
紅黑樹並無想象的那麼難, 初學者以爲晦澀難讀多是由於狀況太多. 紅黑樹的狀況能夠經過歸結, 經過合併來獲得更少的狀況, 如此能夠加深對紅黑樹的理解. 網絡上的大部分成黑樹的講解由於沒有「合併」. 紅黑樹的五個性質:node
性質1. 節點是紅色或黑色。python
性質2. 根是黑色。算法
性質3. 全部葉子都是黑色(葉子是NIL節點)。bash
性質4. 每一個紅色節點的兩個子節點都是黑色。(從每一個葉子到根的全部路徑上不能有兩個連續的紅色節點)網絡
性質5. 從任一節點到其每一個葉子的全部簡單路徑 都包含相同數目的黑色節點。數據結構
摘自 sgi stl 紅黑樹數據結構定義:svg
typedef bool _Rb_tree_Color_type; const _Rb_tree_Color_type _S_rb_tree_red = false; const _Rb_tree_Color_type _S_rb_tree_black = true; struct _Rb_tree_node_base { typedef _Rb_tree_Color_type _Color_type; typedef _Rb_tree_node_base* _Base_ptr; _Color_type _M_color; _Base_ptr _M_parent; _Base_ptr _M_left; _Base_ptr _M_right; static _Base_ptr _S_minimum(_Base_ptr __x) { while (__x->_M_left != 0) __x = __x->_M_left; return __x; } static _Base_ptr _S_maximum(_Base_ptr __x) { while (__x->_M_right != 0) __x = __x->_M_right; return __x; } }; template <class _Value> struct _Rb_tree_node : public _Rb_tree_node_base { typedef _Rb_tree_node<_Value>* _Link_type; _Value _M_value_field; };
在展開紅黑樹以前, 首先來看看普通二叉搜索樹的插入和刪除. 插入很容易理解, 比當前值大就往右走, 比當前值小就往左走. 詳細展開的是刪除操做.lua
二叉樹的刪除操做有一個技巧, 即在查找到須要刪除的節點 X; 接着咱們找到要麼在它的左子樹中的最大元素節點 M、要麼在它的右子樹中的最小元素節點 M, 並交換(M,X). 此時, M 節點必然至多隻有一個孩子; 最後一個步驟就是用 M 的子節點代替 M 節點就完成了. 因此, 全部的刪除操做最後都會歸結爲刪除一個至多隻有一個孩子的節點, 而咱們刪除這個節點後, 用它的孩子替換就行了. 將會看到 sgi stl map 就是這樣的策略.spa
在紅黑樹刪除操做講解中, 咱們假設代替 M 的節點是 N(下面的講述再也不出現 M).
插入新節點老是紅色節點, 由於不會破壞性質 5, 儘量維持全部性質.
假設, 新插入的節點爲 N, N 節點的父節點爲 P, P 的兄弟(N 的叔父)節點爲 U, P 的父親(N 的爺爺)節點爲 G. 因此有以下的印象圖:
插入節點的關鍵是:
插入算法詳解以下, 走一遍紅黑樹維持其性質的過程:
第 0.0 種狀況, N 爲根節點, 直接 N->黑. over
第 0.1 種狀況, N 的父節點爲黑色, 這不違反紅黑樹的五種性質. over
第 1 種狀況, N,P,U 都紅(G 確定黑). 策略: G->紅, N,P->黑. 此時, G 紅, 若是 G 的父親也是紅, 性質又被破壞了, HACK: 能夠將 GPUN 當作一個新的紅色 N 節點, 如此遞歸調整下去; 特俗的, 若是碰巧將根節點染成了紅色, 能夠在算法的最後強制 root->黑.
第 2 種狀況, P 爲紅, N 爲 P 右孩子, N 爲紅, U 爲黑或缺乏. 策略: 旋轉變換, 從而進入下一種狀況:
第 3 種狀況, 可能由第二種變化而來, 但不是必定: P 爲紅, N 爲 P 左孩子, N 爲紅. 策略: 旋轉, 交換 P,G 顏色, 調整後, 由於 P 爲黑色, 因此不怕 P 的父節點是紅色的狀況. over
紅黑樹的插入就爲上面的三種狀況. 你能夠作鏡像變換從而獲得其餘的狀況.
假設 N 節點見上面普通二叉樹刪除中的定義, P 爲 N 父節點, S 爲 N 的兄弟節點, SL,SR 分別是 S 的左右子節點. 有以下印象圖:
刪除節點的關鍵是:
刪除算法詳解以下, 走一遍紅黑樹維持其性質的過程:
第 0.0 狀況, N 爲根節點. over
第 0.1 狀況, 刪除的節點爲紅. over
第 0.2 狀況, 刪除節點爲黑, N 爲紅. 策略: N->黑, 從新平衡. over
第 1 狀況, N,P,S,SR,SL 都黑. 策略: S->紅. 經過 PN,PS 的黑色節點數量相同了, 但會比其餘路徑多一個, 解決的方法是在 P 上從狀況 0 開始繼續調整. 爲何要這樣呢? HANKS: 由於既然 PN,PS 路徑上的黑節點數量相同並且比其餘路徑會少一個黑節點, 那何不將其總體當作了一個 N 節點! 這是遞歸原理.
第 2 狀況, S 紅, 根據紅黑樹性質 P,SL,SR 必定黑. 策略: 旋轉, 交換 P,S 顏色. 處理後關注的範圍縮小, 下面的狀況對應下面的框圖, 算法從框圖從新開始, 進入下一個狀況:
第 2.1 狀況, S,SL,SR 都黑. 策略: P->黑. S->紅, 由於經過 N 的路徑多了一個黑節點, 經過 S 的黑節點個數不變, 因此維持了性質 5. over. 將看到, sgi stl map 源代碼中將第 2.1 和第 1 狀況合併成一種狀況, 下節展開.
第 2.2.1 狀況, S,SR 黑, SL 紅. 策略: 旋轉, 變換 SL,S 顏色. 從而又進入下一種狀況:
第 2.2.2 狀況, S 黑, SR 紅. 策略: 旋轉, 交換 S,P 顏色, SR->黑色, 從新得到平衡.
上面狀況標號 X.X.X 並非說這些關係是嵌套的, 只是這樣展開容易理解. 此時, 解釋三個地方:
紅黑樹刪除從新調整僞代碼以下:
// 第 0.0 狀況, N 爲根節點. over if N.parent == NULL: return; // 第 0.1 狀況, 刪除的節點爲紅. over if color == RED: return; // 第 0.2 狀況, 刪除節點爲黑, N 爲紅, 簡單變換: N->黑, 從新平衡. over if color == BLACK && N.color == RED: N.color = BLACK; // 第 1 種狀況, N,P,S,SR,SL 都黑. 策略: S->紅. 經過 N,S 的黑色節點數量相同了, 但會比其餘路徑多一個, 解決的方法是在 P 上從狀況 0 開始繼續調整. if N,P,S,SR,SL.color == BLACK: S.color = RED; // 調整節點關係 N = P N.parent = P.parent S = P.paernt.another_child SL = S.left_child SR = S.right_child continue; // 第 2 狀況, S 紅, 根據紅黑樹性質 P,SR,SL 必定黑. 旋轉, 交換 P,S 顏色. 此時關注的範圍縮小, 下面的狀況對應下面的框圖, 算法從框圖從新開始. if S.color == RED: rotate(P); swap(P.color,S.color); // 調整節點關係 S = P.another_child SL = S.left_child SR = S.right_child // 第 2.1 狀況, S,SL,SR 都黑. 策略: P->黑. S->紅, 由於經過 N 的路徑多了一個黑節點, 經過 S 的黑節點個數不變, 因此維持了性質 5. over. 將看到, sgi stl map 源代碼中將第 2.1 和第 1 狀況合併成一種狀況, 下節展開. if S,SL,SR.color == BLACK: P.color = BLACK; S.color = RED; return // 第 2.2.1 狀況, S,SR 黑, SL 紅. 策略: 旋轉, 變換 SL,S 顏色. 從而又進入下一種狀況: if S,SR.color == BLACK && SL.color == RED: rotate(P); swap(S.color,SL.color); // 調整節點關係 S = SL SL = S.left_child SR = S.right_child // 第 2.2.2 狀況, S 黑, SR 紅. 策略: 旋轉, 交換 S,P 顏色. if S.color == BLACK && SR.color == RED: rotate(P); swap(P.color,S.color); return;
因此, 插入的狀況只有三種, 刪除的狀況只有兩種. 上面的分析, 作鏡像處理, 就能獲得插入刪除的所有算法, 腦補吧. 從上面的分析來看, 紅黑樹具備如下特性: 插入刪除操做都是 0(lnN), 且最多旋轉三次.
下節中會重點展開 sgi stl map 的源代碼.
參考文檔: wikipedia
搗亂 2013-9-25