本文將主要講述平衡二叉樹中的紅黑樹,紅黑樹是一種咱們常用的樹,相較於 AVL 樹他不管是增長仍是刪除節點,其結構的變化都能控制在常樹次;在 JDK 中的 TreeMap 一樣也是使用紅黑樹實現的;java
紅黑樹是在AVL 樹平衡條件的基礎上,進一步放寬條件,從而使得紅黑樹在動態變化的時候,其結構的變化在常數次;其標準大體能夠表示爲; 任一節點左、右子樹的高度,相差不得超過兩倍。node
同他的名字,紅黑樹的節點是有顏色的,如圖所示:學習
其性質以下:this
(2,4)B 樹,若是將紅黑樹的紅色節點和其父節點合併爲一個超級節點,則其結構和(2,4)B 樹 的結構徹底同樣,因此在學習紅黑樹的時候,能夠對照 B 的轉換方法,幫助理解;3d
public class RBTree<T extends Comparable<T>> { private static final boolean RED = false; private static final boolean BLACK = true; private RBTNode<T> root; // 根結點 public class RBTNode<T extends Comparable<T>> { boolean color; // 顏色 T key; // 關鍵字(鍵值) RBTNode<T> left; // 左孩子 RBTNode<T> right; // 右孩子 RBTNode<T> parent; // 父結點 } }
由於一般狀況下插入的節點會標記爲紅色,那麼就有可能致使兩個紅色的節點練成父子,因此須要經過一下方法修復;code
如圖所示,若是插入的紅色節點和父節點一塊兒組成了3個關鍵碼的超級節點,在 B 樹的角度上則只須要從新標記顏色,使黑色節點位於中間便可;表如今紅黑樹中就須要進行旋轉操做,如圖:blog
雙紅節點同邊:rem
雙紅節點異邊:class
其實在這裏若是忽略顏色,其旋轉操做就可 AVL 樹是同樣的;那麼在實現的時候一樣可使用以前講過的 3+4 重構
;基礎
如圖所示,若是紅色節點上移後,同其父節點組成的超級節點是4個關鍵碼,則發生了上溢,須要將其分裂爲兩個節點;但此時表如今紅黑樹上其結構並未發生變化,因此只須要從新染色便可;
如圖所示:
當刪除黑節點的時候,會使得該分支的黑高度下降,從而不知足每一個分支的黑高度相等,因此下面將刪除黑節點分紅幾種狀況進行修復;
當刪除的節點是黑色節點,且其兄弟節點是黑色,同時有紅孩子的時候;若是轉化爲 (2,4)B 樹
:
如圖所示:
若是父節點是紅色,有黑色兄弟節點,而且沒有紅色孩子:
轉化爲 (2,4)B 樹
:
如圖所示,
若是父節點是黑色,有黑色兄弟節點,而且沒有紅色孩子:
轉化爲 (2,4)B 樹
:
如圖所示:
bb-2-r
同樣,可是其父節點爲黑色;O(logn)
次;若是父節點是黑色,有紅色兄弟節點:
轉化爲 (2,4)B 樹
:
如圖所示:
private RBTNode<T> search(RBTNode<T> x, T key) { if (x == null) return x; int cmp = key.compareTo(x.key); if (cmp < 0) return search(x.left, key); else if (cmp > 0) return search(x.right, key); else return x; }
public void insert(T key) { insert(new RBTNode<T>(key, BLACK, null, null, null)); } private void insert(RBTNode<T> node) { int cmp; RBTNode<T> y = null; RBTNode<T> x = this.root; // 1. 將紅黑樹看成一顆二叉查找樹,將節點添加到二叉查找樹中。 while (x != null) { y = x; cmp = node.key.compareTo(x.key); if (cmp < 0) x = x.left; else x = x.right; } node.parent = y; if (y != null) { cmp = node.key.compareTo(y.key); if (cmp < 0) y.left = node; else y.right = node; } else { this.root = node; } // 2. 設置節點的顏色爲紅色 node.color = RED; // 3. 將它從新修正爲一顆二叉查找樹 insertFixUp(node); } private void insertFixUp(RBTNode<T> node) { RBTNode<T> parent, gparent; // 若「父節點存在,而且父節點的顏色是紅色」 while (((parent = parentOf(node)) != null) && isRed(parent)) { gparent = parentOf(parent); //若「父節點」是「祖父節點的左孩子」 if (parent == gparent.left) { // Case 1條件:叔叔節點是紅色 RBTNode<T> uncle = gparent.right; if ((uncle != null) && isRed(uncle)) { setBlack(uncle); setBlack(parent); setRed(gparent); node = gparent; continue; } // Case 2條件:叔叔是黑色,且當前節點是右孩子 if (parent.right == node) { RBTNode<T> tmp; leftRotate(parent); tmp = parent; parent = node; node = tmp; } // Case 3條件:叔叔是黑色,且當前節點是左孩子。 setBlack(parent); setRed(gparent); rightRotate(gparent); } else { //若「z的父節點」是「z的祖父節點的右孩子」 // Case 1條件:叔叔節點是紅色 RBTNode<T> uncle = gparent.left; if ((uncle != null) && isRed(uncle)) { setBlack(uncle); setBlack(parent); setRed(gparent); node = gparent; continue; } // Case 2條件:叔叔是黑色,且當前節點是左孩子 if (parent.left == node) { RBTNode<T> tmp; rightRotate(parent); tmp = parent; parent = node; node = tmp; } // Case 3條件:叔叔是黑色,且當前節點是右孩子。 setBlack(parent); setRed(gparent); leftRotate(gparent); } } } /* * 對紅黑樹的節點(x)進行左旋轉 * * 左旋示意圖(對節點x進行左旋): * px px * / / * x y * / \ --(左旋)-. / \ # * lx y x ry * / \ / \ * ly ry lx ly * * */ private void leftRotate(RBTNode<T> x) { // 設置x的右孩子爲y RBTNode<T> y = x.right; // 將 「y的左孩子」 設爲 「x的右孩子」; // 若是y的左孩子非空,將 「x」 設爲 「y的左孩子的父親」 x.right = y.left; if (y.left != null) y.left.parent = x; // 將 「x的父親」 設爲 「y的父親」 y.parent = x.parent; if (x.parent == null) { this.root = y; // 若是 「x的父親」 是空節點,則將y設爲根節點 } else { if (x.parent.left == x) x.parent.left = y; // 若是 x是它父節點的左孩子,則將y設爲「x的父節點的左孩子」 else x.parent.right = y; // 若是 x是它父節點的左孩子,則將y設爲「x的父節點的左孩子」 } // 將 「x」 設爲 「y的左孩子」 y.left = x; // 將 「x的父節點」 設爲 「y」 x.parent = y; } /* * 對紅黑樹的節點(y)進行右旋轉 * * 右旋示意圖(對節點y進行左旋): * py py * / / * y x * / \ --(右旋)-. / \ # * x ry lx y * / \ / \ # * lx rx rx ry * */ private void rightRotate(RBTNode<T> y) { // 設置x是當前節點的左孩子。 RBTNode<T> x = y.left; // 將 「x的右孩子」 設爲 「y的左孩子」; // 若是"x的右孩子"不爲空的話,將 「y」 設爲 「x的右孩子的父親」 y.left = x.right; if (x.right != null) x.right.parent = y; // 將 「y的父親」 設爲 「x的父親」 x.parent = y.parent; if (y.parent == null) { this.root = x; // 若是 「y的父親」 是空節點,則將x設爲根節點 } else { if (y == y.parent.right) y.parent.right = x; // 若是 y是它父節點的右孩子,則將x設爲「y的父節點的右孩子」 else y.parent.left = x; // (y是它父節點的左孩子) 將x設爲「x的父節點的左孩子」 } // 將 「y」 設爲 「x的右孩子」 x.right = y; // 將 「y的父節點」 設爲 「x」 y.parent = x; }
public void remove(T key) { RBTNode<T> node; if ((node = search(root, key)) != null) remove(node); } private void remove(RBTNode<T> node) { RBTNode<T> child, parent; boolean color; // 被刪除節點的"左右孩子都不爲空"的狀況。 if ((node.left != null) && (node.right != null)) { // 被刪節點的後繼節點。(稱爲"取代節點") // 用它來取代"被刪節點"的位置,而後再將"被刪節點"去掉。 RBTNode<T> replace = node; // 獲取後繼節點 replace = replace.right; while (replace.left != null) replace = replace.left; // "node節點"不是根節點(只有根節點不存在父節點) if (parentOf(node) != null) { if (parentOf(node).left == node) parentOf(node).left = replace; else parentOf(node).right = replace; } else { // "node節點"是根節點,更新根節點。 this.root = replace; } // child是"取代節點"的右孩子,也是須要"調整的節點"。 // "取代節點"確定不存在左孩子!由於它是一個後繼節點。 child = replace.right; parent = parentOf(replace); // 保存"取代節點"的顏色 color = colorOf(replace); // "被刪除節點"是"它的後繼節點的父節點" if (parent == node) { parent = replace; } else { // child不爲空 if (child != null) setParent(child, parent); parent.left = child; replace.right = node.right; setParent(node.right, replace); } replace.parent = node.parent; replace.color = node.color; replace.left = node.left; node.left.parent = replace; if (color == BLACK) removeFixUp(child, parent); node = null; return; } if (node.left != null) { child = node.left; } else { child = node.right; } parent = node.parent; // 保存"取代節點"的顏色 color = node.color; if (child != null) child.parent = parent; // "node節點"不是根節點 if (parent != null) { if (parent.left == node) parent.left = child; else parent.right = child; } else { this.root = child; } if (color == BLACK) removeFixUp(child, parent); node = null; } private void removeFixUp(RBTNode<T> node, RBTNode<T> parent) { RBTNode<T> other; while ((node == null || isBlack(node)) && (node != this.root)) { if (parent.left == node) { other = parent.right; if (isRed(other)) { // Case 1: x的兄弟w是紅色的 setBlack(other); setRed(parent); leftRotate(parent); other = parent.right; } if ((other.left == null || isBlack(other.left)) && (other.right == null || isBlack(other.right))) { // Case 2: x的兄弟w是黑色,且w的倆個孩子也都是黑色的 setRed(other); node = parent; parent = parentOf(node); } else { if (other.right == null || isBlack(other.right)) { // Case 3: x的兄弟w是黑色的,而且w的左孩子是紅色,右孩子爲黑色。 setBlack(other.left); setRed(other); rightRotate(other); other = parent.right; } // Case 4: x的兄弟w是黑色的;而且w的右孩子是紅色的,左孩子任意顏色。 setColor(other, colorOf(parent)); setBlack(parent); setBlack(other.right); leftRotate(parent); node = this.root; break; } } else { other = parent.left; if (isRed(other)) { // Case 1: x的兄弟w是紅色的 setBlack(other); setRed(parent); rightRotate(parent); other = parent.left; } if ((other.left == null || isBlack(other.left)) && (other.right == null || isBlack(other.right))) { // Case 2: x的兄弟w是黑色,且w的倆個孩子也都是黑色的 setRed(other); node = parent; parent = parentOf(node); } else { if (other.left == null || isBlack(other.left)) { // Case 3: x的兄弟w是黑色的,而且w的左孩子是紅色,右孩子爲黑色。 setBlack(other.right); setRed(other); leftRotate(other); other = parent.left; } // Case 4: x的兄弟w是黑色的;而且w的右孩子是紅色的,左孩子任意顏色。 setColor(other, colorOf(parent)); setBlack(parent); setBlack(other.left); rightRotate(parent); node = this.root; break; } } } if (node != null) setBlack(node); }