紅黑樹是一棵二叉查找樹,它在每一個結點上增長了一個存儲爲來表示結點的顏色,能夠RED或BLACK。經過對任意一條從根到葉子的簡單路徑上各個結點的顏色進行約束,紅黑樹確保沒有一條路徑會比其餘路徑長出2倍,於是是近似於平衡。node
樹中每一個結點都包含5個屬性:color、key、left、right和p。若是一個結點沒有子結點或者父結點,則該結點相應指針屬性值爲NIL,視爲外結點同樣的葉子結點。c++
每一棵紅黑樹都須要知足下面的性質:指針
爲了方便和節省空間,常常在紅黑樹T中設置一個屬性T.nil,而後全部結點的空指針指向其:code
從某個結點x出發(不含該結點)到達一個葉結點的任意一條簡單路徑上的黑色結點個數稱爲該結點的黑高,記爲bh(x)。blog
一棵有n個內部結點的紅黑樹的高度至多爲2lg(n+1),這保證了其查找操做都在O(lgn)內能完成class
在插入和刪除操做後,紅黑樹的性質可能會被破壞,這時候就要經過旋轉
來進行調整。旋轉分爲2種:左旋和右旋。當在某個結點x上左左旋時,x右孩子不爲T.nil結點,則左旋後,x成爲y的左孩子,y的左孩子成爲x的右孩子。右旋同樣的道理。原理
一棵紅黑樹包括兩個結點:bfc
struct RBT { node * root; node * nil; };
LEFT_ROTATE(T,x) { y = x.right; x.right = y.left; if y.left != T.nil y.left.p = x; y.p = x.p; if x.p == T.nil T.root = y; elsif x == x.p.left x.p.left = y; else x.p.right = y; y.left = x; x.p = y; } //RIGHT_ROTATE相似
講道理插入原理和二叉查找樹差很少,只不過多了一個維護性質的過程。二叉樹
RB_INSERT(T,z) { y = T.nil; x = T.root; while x != T.nil { y = x; if z.key < x.key x = x.left; else x = x.right; } z.p = y; if y == T.nil T.root = z; elsif z.key < y.left y.left = z; else y.right = z; z.left = T.nil; z.right = T.nil; z.color = RED; RB_INSERT_FIXUP(T,z); } RB_INSERT_FIXUP(T,z) { while z.p.color == RED { if z.p == x.p.p.left { y = z.p.p.right; if y.color == RED { //case 1 z.p.color = BLACK; y.color = BLACK; z.p.p.color = RED; z = z.p.p; } elsif z == z.p.right { //case 2 z = z.p; LEFT_ROTATE(T,z); } z.p.color = BLACK; //case 3 z.p.p.color = RED; RIGHT_ROTATE(T,z.p.p); } else //直接是上個代碼left<->right調換便可 } T.root.color = BLACK; }
其實有6種狀況能夠改變紅黑樹的性質,可是因爲是對稱的,因此只給了一邊的代碼,具體狀況圖示:im
刪除其實和查找二叉樹的刪除相似,只是多了一個維護性質的過程,先貼出代碼:
//v爲根的子樹替換u爲根的子樹 RB_TRANSPLANT(T,u,v) { if u.p == T.nil T.root = v; elsif u == u.p.left u.p.left = v; else u.p.right = v; v.p = u.p; } RB_DELETE(T,z) { y = z; y_original_color = y.color; if z.left == T.nil x = z.right; RB_TRANSPLANT(T,z,z.right); elsif z.right == T.nil x = z.left; RB_TRANSPLANT(T,z,z.left); else y = TREE_MINIMUM(z.right); y_original_color = y.color; x = y.right; if y.p == z x.p = y; else RB_TRANSPLANT(T,y,y.right); y.right = z.right; y.right.p = y; RB_TRANSPLANT(T,z,y); y.left = z.left; y.left.p = y; y.color = z.color; //只有顏色爲黑纔會破壞性質 if y_original_color == BLACK RE_DELETE_FIXUP(T,x); } RB_DELETE_FIXUP(T,x) { while x != T.root and x.color == BLACK { if x== z.p.left w = x.p.right; if w.color == RED //case 1 w.color = BLACK; x.p.color = RED; LEFT_ROTATE(T,x.p); w = x.p.right; if w.left.color == BLACK and w.right.color == BLACK //case 2 w.color = RED; x = x.p; eleif w.right.color == BLACK //case 3 w.left.color = BLACK; w.color = RED; RIGHT_ROTATE(T,w); w = x.p.right; w.color = x.p.right; // case 4 x.p.color = BLACK; w.right.color = BLACK; LEFT_ROTATE(T,x.p); x = T.root; else //和上面同樣,將left互換right } }
有8種狀況,可是是對稱的,因此只給出4種狀況的代碼,具體看圖: