紅黑樹是一種搜索二叉樹,並且也是一種平衡搜索二叉樹,它能夠保證在最壞的狀況下的基本的操做的時間複雜度爲O(lgn)。ide
紅黑樹具備以下的性質:post
紅黑樹的旋轉測試
注意這個旋轉和AVL樹的旋轉不同,紅黑樹的旋轉只有左旋和右旋。那爲何要旋轉呢,由於是在插入和刪除節點後,這棵樹可能就不知足紅黑樹的性質了,因此須要作一些從新着色和旋轉的操做。this
下面看一下左旋和右旋的示意圖。spa
左旋能夠理解爲,以那個節點左旋的,這個節點就會成爲本身右孩子的左孩子。code
右旋能夠理解爲,以那個節點右旋的,這個節點就會成爲本身左孩子的右孩子。blog
下面是左旋的僞代碼 假設 x.right !=T.nil 且根結點的父結點爲T.nilget
LEFT-ROTATE(T, x) y = x.right // x的右孩子爲y x.right = y.left // 將 「y的左孩子」 設爲 「x的右孩子」,即 將β設爲x的右孩子 if y.left != T.nil // 將 「x」 設爲 「y的左孩子的父親」,即 將β的父親設爲x y.left.p = x y.p = x.p // 將 「x的父親」 設爲 「y的父親」
if x.p == T.nil // 若是x的父親爲null,因此x節點是根節點,這時就把y設爲根節點
T.root = y
elseif x == x.p.left // 若是x是父節點的左孩子,就把y設置x父節點的左孩子
x.p.left = y
else x.p.right = y // 若是x是父節點的右孩子,就把y設置x父節點的右孩子
y.left = x // 把x設置爲y的左孩子,
x.p = y // 把y設爲x的父親
右旋的僞代碼hash
RIGHT-ROTATE(T, y) x = y.left // y的左孩子爲x y.left = x.right // 將 「x的右孩子」 設爲 「y的左孩子」,即 將β設爲x的右孩子 if x.right != T.nil // 將 「y」 設爲 「x的右孩子的父親」,即 將β的父親設爲y x.right.p = y x.p = y.p // 將 「y的父親」 設爲 「x的父親」 if y.p == T.nil // 若是y的父親爲null,因此y節點是根節點,這時就把x設爲根節點 T.root = x elseif y == y.p.left // 若是y是父節點的左孩子,就把x設置y父節點的左孩子 y.p.left = x else y.p.right = x // 若是y是父節點的右孩子,就把x設置y父節點的右孩子 x.left = y // 把y設置爲x的右孩子, y.p = x // 把x設爲y的父親
紅黑樹的插入it
紅黑樹的插入前面的邏輯和普通的二叉搜索樹的插入邏輯差很少。這裏再也不多說,主要差異在於插入後可能會破壞紅黑樹的性質。咱們主要來看看修復的僞代碼。
先把要插入節點設爲紅色,爲何設爲紅色而不是黑色呢,這個能夠先看一下紅黑樹的性質,若是把插入節點設置黑色,那麼性質1234都不違背,可是性質5確定違背。若是設置爲紅色呢,則可能違背2和4,注意是可能。也有可能插入的紅色節點後,依然是一個紅黑樹。
1 若是插入的節點是根節點。則把節點顏色從紅色變爲黑色便可。
2 若是插入的節點不是根節點,可是待插入位置的父節點是黑色。插入紅色節點不會違背任何紅黑樹性質。
3 若是不是上面兩種狀況,則狀況要複雜了。分爲三種狀況處理。下面先看一下僞代碼。
RB-INSERT-FIXUP(T, z) while z.p.color == RED // 若「當前節點(z)的父節點是紅色」,則進行如下處理。 if z.p == z.p.p.left // 若「z的父節點」是「z的祖父節點的左孩子」,則進行如下處理。 y = z.p.p.right // 將y設置爲「z的叔叔節點(z的祖父節點的右孩子)」 if y.color == RED // Case 1條件:叔叔是紅色 z.p.color = BLACK ▹ Case 1 // (01) 將「父節點」設爲黑色。 y.color = BLACK ▹ Case 1 // (02) 將「叔叔節點」設爲黑色。 z.p.p.color = RED ▹ Case 1 // (03) 將「祖父節點」設爲「紅色」。 z = z.p.p ▹ Case 1 // (04) 將「祖父節點」設爲「當前節點」(紅色節點) else if z == z.p.right // Case 2條件:叔叔是黑色,且當前節點是右孩子 z = z.p ▹ Case 2 // (01) 將「父節點」做爲「新的當前節點」。 LEFT-ROTATE(T, z) ▹ Case 2 // (02) 以「新的當前節點」爲支點進行左旋。 z.p.color = BLACK ▹ Case 3 // Case 3條件:叔叔是黑色,且當前節點是左孩子。(01) 將「父節點」設爲「黑色」。 z.p.p.color = RED ▹ Case 3 // (02) 將「祖父節點」設爲「紅色」。 RIGHT-ROTATE(T, z.p.p) ▹ Case 3 // (03) 以「祖父節點」爲支點進行右旋。 else (same as then clause with "right" and "left" exchanged) // 若「z的父節點」是「z的祖父節點的右孩子」,將上面的操做中「right」和「left」交換位置,而後依次執行。 T.root.color = BLACK
RB-INSERT-FIXUP(T, z) while z.p.color == RED // 若「當前節點(z)的父節點是紅色」,則進行如下處理。 if z.p = z.p.p.right // 若「z的父節點」是「z的祖父節點的右孩子」,則進行如下處理。 y = z.p.p.left // 將y設置爲「z的叔叔節點(z的祖父節點的左孩子)」 if y.color == RED // Case 1條件:叔叔是紅色 z.p.color = BLACK ▹ Case 1 // (01) 將「父節點」設爲黑色。 y.color = BLACK ▹ Case 1 // (02) 將「叔叔節點」設爲黑色。 z.p.p.color = RED ▹ Case 1 // (03) 將「祖父節點」設爲「紅色」。 z = z.p.p ▹ Case 1 // (04) 將「祖父節點」設爲「當前節點」(紅色節點) else if z == z.p.left // Case 2條件:叔叔是黑色,且當前節點是左孩子 z = z.p ▹ Case 2 // (01) 將「父節點」做爲「新的當前節點」。 RIGHT-ROTATE(T, z) ▹ Case 2 // (02) 以「新的當前節點」爲支點進行右旋。 z.p.color = BLACK ▹ Case 3 // Case 3條件:叔叔是黑色,且當前節點是右孩子。(01) 將「父節點」設爲「黑色」。 z.p.p.color = RED ▹ Case 3 // (02) 將「祖父節點」設爲「紅色」。 LEFT-ROTATE(T, z.p.p) ▹ Case 3 // (03) 以「祖父節點」爲支點進行左旋。 else (same as then clause with "right" and "left" exchanged) // 若「z的父節點」是「z的祖父節點的右孩子」,將上面的操做中「right」和「left」交換位置,而後依次執行。 T.root.color = BLACK
1 當父節點是祖父節點的左孩子時
條件 | 處理策略 | |
case1 | 父節點是紅色,叔叔節點紅色 | 1 將父節點設置黑色 2 將叔叔節點設置黑色 3 將祖父節點設置紅色 4將祖父節點設爲當前節點繼續 |
case2 | 父節點是紅色,叔叔是黑色,且當前節點是右孩子 | 1 將「父節點」做爲「新的當前節點」。 2 以「新的當前節點」爲支點進行左旋 |
case3 | 父節點是紅色,叔叔是黑色,且當前節點是左孩子 | 1 以「新的當前節點」將「父節點」設爲「黑色」 2 將「祖父節點」設爲「紅色」 3 以「祖父節點」爲支點進行右旋 |
2 當父節點是祖父節點的右孩子時
條件 |
處理策略 |
|
case1 | 父節點是紅色,叔叔節點紅色 | 1 將父節點設置黑色 2 將叔叔節點設置黑色 3 將祖父節點設置紅色 4將祖父節點設爲當前節點繼續 |
case2 | 父節點是紅色,叔叔是黑色,且當前節點是右孩子 | 1 將「父節點」做爲「新的當前節點」。 2 以「新的當前節點」爲支點進行右旋 |
case3 | 父節點是紅色,叔叔是黑色,且當前節點是左孩子 | 1 以「新的當前節點」將「父節點」設爲「黑色」 2 將「祖父節點」設爲「紅色」 3 以「祖父節點」爲支點進行左旋 |
這就是全部的關於紅黑樹的應對狀況。其實不用太緊張,這就像是公式同樣,遇到什麼狀況,作什麼操做是必定的。因此不太明白的話,就動手作幾遍。就會加深理解了,
刪除操做相對於插入要更復雜一些。想像一下,在二叉樹刪除時,咱們分爲三種狀況,刪除節點只有左孩子,刪除節點只有右孩子,刪除節點有兩個孩子的狀況,其中刪除節點有兩個孩子節點的時候,須要找出
刪除節點的後繼節點,這時後繼節點確定只有右孩子,把後繼節點移到待刪除的節點,其實就至關於刪除了後繼節點。而後刪除又轉化爲只有右孩子的狀況。
而紅黑樹的刪除只是在這個狀況上,多了一個顏色屬性,還有刪除可能違背紅黑樹的性質,那什麼狀況下刪除節點會違背紅黑樹的性質呢。當刪除的節點顏色是黑色的時候,會違背紅黑樹的性質。
爲何刪除紅色節點不會違背呢,
那就看看紅黑樹的性質,看看會不會違背吧,性質1確定不會,由於刪除前是一個紅黑樹,刪除節點確定不會破壞這個性質,由於刪除的節點的紅色的,因此刪除的節點不是根節點,根節點依然是黑色的。性質3也確定不會違背了。
性質4,也不會,由於刪除的紅色節點,因此刪除節點的子節點和父節點都是黑色的。性質5也不會,由於刪除的是紅色節點。不會影響每條路徑上黑色節點的數目。
那麼刪除節點爲黑色有分爲那些狀況呢,
1 當刪除的節點爲根節點時,若是是它的紅色孩子節點移到根節點,這時只要把節點置爲黑色便可,
2 當刪除節點不是根節點。那麼若是它的孩子節點是紅色的,這時也是隻要把節點置爲黑色便可。
若是不是以上兩種狀況,就有點複雜了,先看下面的僞代碼。
RB-DELETE-FIXUP(T, x) while x ≠ T.root and x.color == BLACK if x == x.p.left // 若是x是它父親的左孩子 w = x.p.right // 若 「x」是「它父節點的左孩子」,則設置 「w」爲「x的兄弟」(即w爲x父節點的右孩子) if w.color == RED // Case 1: x是「黑+黑」節點,x的兄弟是紅色。(此時x的父節點和x的叔叔節點的子節點都是黑節點)。 w.color = BLACK ▹ Case 1 // (01) 將x的兄弟節點設爲「黑色」。 x.p.color = RED ▹ Case 1 // (02) 將x的父節點設爲「紅色」。 LEFT-ROTATE(T, x.p) ▹ Case 1 // (03) 對x的父節點進行左旋。 w = x.p.right ▹ Case 1 // (04) 左旋後,從新設置x的兄弟節點。 if w.left.color == BLACK and w.right.color == BLACK // Case 2: x是「黑+黑」節點,x的兄弟節點是黑色,x的兄弟節點的兩個孩子都是黑色。 w.color = RED ▹ Case 2 // (01) 將x的兄弟節點設爲「紅色」。 x = x.p ▹ Case 2 // (02) 設置「x的父節點」爲「新的x節點」。 else if w.right.color == BLACK // Case 3: x是「黑+黑」節點,x的兄弟節點是黑色;x的兄弟節點的左孩子是紅色,右孩子是黑色的。 w.left.color = BLACK ▹ Case 3 // (01) 將x兄弟節點的左孩子設爲「黑色」。 w.color = RED ▹ Case 3 // (02) 將x兄弟節點設爲「紅色」。 RIGHT-ROTATE(T, w) ▹ Case 3 // (03) 對x的兄弟節點進行右旋。 w = x.p.right ▹ Case 3 // (04) 右旋後,從新設置x的兄弟節點。 w.color = x.p.color ▹ Case 4 // Case 4: x是「黑+黑」節點,x的兄弟節點是黑色;x的兄弟節點的右孩子是紅色的。(01) 將x父節點顏色 賦值給 x的兄弟節點。 x.p.color = BLACK ▹ Case 4 // (02) 將x父節點設爲「黑色」。 w.right.color = BLACK ▹ Case 4 // (03) 將x兄弟節點的右子節設爲「黑色」。 LEFT-ROTATE(T, x.p) ▹ Case 4 // (04) 對x的父節點進行左旋。 x = T.root ▹ Case 4 // (05) 設置「x」爲「根節點」。 else (same as then clause with "right" and "left" exchanged) // 若 「x」是「它父節點的右孩子」,將上面的操做中「right」和「left」交換位置,而後依次執行。 x.color = BLACK
RB-DELETE-FIXUP(T, x) while x ≠ T.root and x.color == BLACK if x == x.p.right // 若是x是它父親的右孩子 w = x.p.left // 若 「x」是「它父節點的右孩子」,則設置 「w」爲「x的兄弟」(即w爲x父節點的左孩子) if w.color == RED // Case 1: x是「黑+黑」節點,x的兄弟是紅色。(此時x的父節點和x的叔叔節點的子節點都是黑節點)。 w.color = BLACK ▹ Case 1 // (01) 將x的兄弟節點設爲「黑色」。 x.p.color = RED ▹ Case 1 // (02) 將x的父節點設爲「紅色」。 RIGHT-ROTATE(T, x.p) ▹ Case 1 // (03) 對x的父節點進行右旋。 w = x.p.left ▹ Case 1 // (04) 右旋後,從新設置x的兄弟節點。 if w.left.color == BLACK and w.right.color == BLACK // Case 2: x是「黑+黑」節點,x的兄弟節點是黑色,x的兄弟節點的兩個孩子都是黑色。 w.color = RED ▹ Case 2 // (01) 將x的兄弟節點設爲「紅色」。 x = x.p ▹ Case 2 // (02) 設置「x的父節點」爲「新的x節點」。 else if w.left.color == BLACK // Case 3: x是「黑+黑」節點,x的兄弟節點是黑色;x的兄弟節點的右孩子是紅色,左孩子是黑色的。 w.right.color = BLACK ▹ Case 3 // (01) 將x兄弟節點的右孩子設爲「黑色」。 w.color = RED ▹ Case 3 // (02) 將x兄弟節點設爲「紅色」。 LEFT-ROTATE(T, w) ▹ Case 3 // (03) 對x的兄弟節點進行左旋。 w = x.p.left ▹ Case 3 // (04) 左旋後,從新設置x的兄弟節點。 w.color = x.p.color ▹ Case 4 // Case 4: x是「黑+黑」節點,x的兄弟節點是黑色;x的兄弟節點的左孩子是紅色的。(01) 將x父節點顏色 賦值給 x的兄弟節點。 x.p.color = BLACK ▹ Case 4 // (02) 將x父節點設爲「黑色」。 w.left.color = BLACK ▹ Case 4 // (03) 將x兄弟節點的左子節設爲「黑色」。 RIGHT-ROTATE(T, x.p) ▹ Case 4 // (04) 對x的父節點進行右旋。 x = T.root ▹ Case 4 // (05) 設置「x」爲「根節點」。 else (same as then clause with "right" and "left" exchanged) // 若 「x」是「它父節點的左孩子」,將上面的操做中「right」和「left」交換位置,而後依次執行。 x.color = BLACK
前提條件 x節點不是根節點,而且x的顏色是紅色的。而且x是父節點的左孩子
條件 |
處理策略 |
|
case1 | 兄弟節點是紅色的 |
1 將x的兄弟節點設爲黑色。 2 將x的父節點設爲紅色。 3 對x的父節點進行左旋。 4 左旋後,從新設置x的兄弟節點。 |
case2 | x的兄弟節點是黑色,x的兄弟節點的兩個孩子都是黑色 | 1 將x的兄弟節點設爲紅色。 2 設置「x的父節點」爲「新的x節點」。 |
case3 | x的兄弟節點是黑色;x的兄弟節點的左孩子是紅色,右孩子是黑色的。 | 1 將x兄弟節點的左孩子設爲「黑色」。 2 將x兄弟節點設爲紅色。 3 對x的兄弟節點進行右旋。 4 右旋後,從新設置x的兄弟節點。 |
case4 | x的兄弟節點是黑色;x的兄弟節點的右孩子是紅色的,x的兄弟節點的左孩子任意顏色。 | 1 將x父節點顏色 賦值給 x的兄弟節點。 2 將x父節點設爲「黑色」。 3 將x兄弟節點的右子節設爲「黑色」。 4 對x的父節點進行左旋。 5 設置「x」爲「根節點」。 |
前提條件 x節點不是根節點,而且x的顏色是紅色的。而且x是父節點的右孩子
條件 |
處理策略 |
|
case1 | 兄弟節點是紅色的 |
1 將x的兄弟節點設爲黑色。 2 將x的父節點設爲紅色。 3 對x的父節點進行右旋。 4 右旋後,從新設置x的兄弟節點。 |
case2 | x的兄弟節點是黑色,x的兄弟節點的兩個孩子都是黑色 |
1 將x的兄弟節點設爲紅色。 2 設置「x的父節點」爲「新的x節點」。 |
case3 | x的兄弟節點是黑色;x的兄弟節點的左孩子是紅色,右孩子是黑色的。 |
1 將x兄弟節點的右孩子設爲「黑色」。 2 將x兄弟節點設爲紅色。 3 對x的兄弟節點進行左旋。 4 左旋後,從新設置x的兄弟節點。 |
case4 | x的兄弟節點是黑色;x的兄弟節點的右孩子是紅色的,x的兄弟節點的左孩子任意顏色。 | 1 將x父節點顏色 賦值給 x的兄弟節點。 2 將x父節點設爲「黑色」。 3 將x兄弟節點的左子節設爲「黑色」。 4 對x的父節點進行右旋。 5 設置「x」爲「根節點」。 |
JAVA版本實現
package cn.damai.maitix.tic.devut.service; /** * Created by dupang on 2017/11/12. */ public class RBTreeNode<T> { /** * 節點的左孩子 */ private RBTreeNode<T> left; /** * 節點的右孩子 */ private RBTreeNode<T> right; /** * 節點的父親 */ private RBTreeNode<T> parent; /** * 節點的顏色 */ private Boolean color ; /** * 節點的值 */ private T value; public RBTreeNode() { } public RBTreeNode(RBTreeNode<T> left, RBTreeNode<T> right, RBTreeNode<T> parent, T value, Boolean color) { this.left = left; this.right = right; this.parent = parent; this.value = value; this.color = color; } public RBTreeNode<T> getLeft() { return left; } public void setLeft(RBTreeNode<T> left) { this.left = left; } public RBTreeNode<T> getRight() { return right; } public void setRight(RBTreeNode<T> right) { this.right = right; } public RBTreeNode<T> getParent() { return parent; } public void setParent(RBTreeNode<T> parent) { this.parent = parent; } public T getValue() { return value; } public void setValue(T value) { this.value = value; } public Boolean getColor() { return color; } public void setColor(Boolean color) { this.color = color; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } RBTreeNode<?> that = (RBTreeNode<?>)o; if (left != null ? !left.equals(that.left) : that.left != null) { return false; } if (right != null ? !right.equals(that.right) : that.right != null) { return false; } if (parent != null ? !parent.equals(that.parent) : that.parent != null) { return false; } if (color != null ? !color.equals(that.color) : that.color != null) { return false; } return value != null ? value.equals(that.value) : that.value == null; } @Override public int hashCode() { int result = left != null ? left.hashCode() : 0; result = 31 * result + (right != null ? right.hashCode() : 0); result = 31 * result + (parent != null ? parent.hashCode() : 0); result = 31 * result + (color != null ? color.hashCode() : 0); result = 31 * result + (value != null ? value.hashCode() : 0); return result; } }
測試類
package cn.damai.maitix.tic.devut.service; /** * Created by dupang on 2017/11/12. */ public class RBTreeTest { private static final Boolean RED = true; private static final Boolean BLACK = false; private static final RBTreeNode<Integer> NULL_NODE = new RBTreeNode<>(null, null, null, null, BLACK); public static void main(String[] args) { int[] values = new int[] {18, 5, 3, 9, 2, 13, 32}; //初始化一個表示樹的根節點 RBTreeNode<Integer> root = new RBTreeNode<>(NULL_NODE, NULL_NODE, NULL_NODE, null, BLACK); //遍歷插入 for (Integer value : values) { //初始化要插入的節點 RBTreeNode<Integer> treeNode = new RBTreeNode<>(NULL_NODE, NULL_NODE, NULL_NODE, value, RED); RBTreeNode<Integer> treeNode2 = new RBTreeNode<>(NULL_NODE, NULL_NODE, NULL_NODE, value, RED); System.out.println(treeNode == treeNode2); rbInsert(root, treeNode); } //中序遍歷 inOrderTreeWalk(root); System.out.println(); //先序遍歷 preOrderTreeWalk(root); System.out.println(); //後序遍歷 postOrderTreeWalk(root); System.out.println(); RBTreeNode<Integer> treeNode = treeSearch(root,3); //求最大值 treeMaximum(root); //求最小值 treeMinimum(root); //後繼 treeSuccessor(root); //前驅 treePredecessor(root); } /** * 紅黑樹的插入操做 * * @param root 二叉樹的根 * @param z 要插入的節點 */ public static void rbInsert(RBTreeNode<Integer> root, RBTreeNode<Integer> z) { //聲明一個y,用於記錄while循環中循環節點的位置,也就是插入節點要插入的位置 RBTreeNode<Integer> y = NULL_NODE; //把樹的根節點賦值給x,先從根節點開始尋找插入的點。 RBTreeNode<Integer> x = root; while (!NULL_NODE.equals(x)) { y = x; //若是要插入的值比根節點的值大, if (z.getValue() > x.getValue()) { x = x.getRight(); } else { x = x.getLeft(); } } z.setParent(y); // y是最後找到的插入的位置,就把z的父親設爲y。 //若是y是null,說明是個空樹 if (y.equals(NULL_NODE)) { z.setParent(null); z.setLeft(null); z.setRight(null); z.setValue(z.getValue()); z.setColor(BLACK); } else if (z.getValue() < y.getValue()) { //若是插入的節點比y小,就把y的左孩子設爲z y.setLeft(z); } else { //若是插入的節點比y大,就把y的右孩子設爲z y.setRight(z); } z.setColor(RED); //把插入的節點顏色設爲紅色 rbInsertFixup(root, z); //由於插入節點後可能破壞紅黑樹的性質,因此調用這個方法來修正使基再次成爲紅黑樹 } /** * 插入後修正紅黑樹 * * @param root 根節點 * @param z 當前節點 */ public static void rbInsertFixup(RBTreeNode<Integer> root, RBTreeNode<Integer> z) { while (z.getParent().getColor() == RED) { if (z.getParent() == z.getParent().getParent().getLeft()) { //若是插入節點的父節點是祖父節點的左孩子 RBTreeNode<Integer> y = z.getParent().getParent().getRight(); //y是z的叔叔節點 if (y.getColor() == RED) { //case 1 若是叔叔節點的顏色是紅色的 z.getParent().setColor(BLACK); //case 1 把z的父節點設爲黑色 y.setColor(BLACK); //case 1 把叔叔節點設爲黑色 z.getParent().getParent().setColor(RED); //case 1 把祖父節點設爲紅色 z = z.getParent().getParent(); //case 1 把祖父節點設置爲當前節點繼續操做 } else { if (z == z.getParent().getRight()) { //case 2 若是z是之父節點的右孩子 z = z.getParent(); //case 2 把父節點設爲當前節點繼續操做 leftRotate(root, z); //case 2 把父節點設爲當前節點進行左旋 } z.getParent().setColor(BLACK); //case 3 設置父節點的顏色爲黑色 z.getParent().getParent().setColor(RED); //case 3 設置祖父節點的顏色爲紅色 rightRotate(root, z.getParent().getParent()); //case 3 把祖父節點設爲當前節點進行右旋 } } else { //若是插入節點的父節點是祖父節點的右孩子 RBTreeNode<Integer> y = z.getParent().getParent().getLeft(); //y是z的叔叔節點 if (y.getColor() == RED) { //case 1 若是叔叔節點的顏色是紅色的 z.getParent().setColor(BLACK); //case 1 把z的父節點設爲黑色 y.setColor(BLACK); //case 1 把叔叔節點設爲黑色 z.getParent().getParent().setColor(RED); //case 1 把祖父節點設爲紅色 z = z.getParent().getParent(); //case 1 把祖父節點設置爲當前節點繼續操做 } else { if (z == z.getParent().getLeft()) { //case 2 若是z是之父節點的左孩子 z = z.getParent(); //case 2 把父節點設爲當前節點繼續操做 rightRotate(root, z); //case 2 把父節點設爲當前節點進行右旋 } z.getParent().setColor(BLACK); //case 3 設置父節點的顏色爲黑色 z.getParent().getParent().setColor(RED); //case 3 設置祖父節點的顏色爲紅色 leftRotate(root, z.getParent().getParent()); //case 3 把祖父節點設爲當前節點進行左旋 } } } } /** * 左旋 * * @param root 根節點 * @param x 旋轉的節點 */ public static void leftRotate(RBTreeNode<Integer> root, RBTreeNode<Integer> x) { RBTreeNode<Integer> y = x.getRight(); //假設x的右孩子是y x.setRight(y.getLeft()); // y的左孩子變爲x的右孩子 if (!NULL_NODE.equals(y.getLeft())) { // 若是y的左孩子不爲null,就設置它的父節點爲x y.getLeft().setParent(x); } y.setParent(x.getParent()); //把y的父節點換爲x的父節點 if (NULL_NODE.equals(x.getParent())) { //若是x的父節點爲null,說明x是根節點,就把y設置爲根節點。 y.setParent(root.getParent()); y.setRight(root.getRight()); y.setLeft(root.getLeft()); y.setColor(root.getColor()); y.setValue(root.getValue()); } else if (x == x.getParent().getLeft()) { //若是x是其父節點的左孩子,就設置x的父節點的左孩子爲y x.getParent().setLeft(y); } else { x.getParent().setRight(y); //若是x是其父節點的右孩子,就設置x的父節點的右孩子爲y } y.setLeft(x); //設置y的左孩子爲x x.setParent(y); //設置x的父親爲y } /** * 右旋 * * @param root 根節點 * @param y 旋轉的節點 */ public static void rightRotate(RBTreeNode<Integer> root, RBTreeNode<Integer> y) { RBTreeNode<Integer> x = y.getLeft(); //假設y的左孩子是x y.setLeft(x.getRight()); // y的左孩子變爲x的右孩子 if (!NULL_NODE.equals(x.getRight())) { // 若是y的左孩子不爲null,就設置它的父節點爲x x.getRight().setParent(y); } x.setParent(y.getParent()); //把y的父節點換爲x的父節點 if (x.getRight().equals(y.getParent())) { //若是y的父節點爲null,說明y是根節點,就把x設置爲根節點。 x.setParent(root.getParent()); x.setRight(root.getRight()); x.setLeft(root.getLeft()); x.setColor(root.getColor()); x.setValue(root.getValue()); } else if (y == y.getParent().getLeft()) { //若是y是其父節點的左孩子,就設置y的父節點的左孩子爲x y.getParent().setLeft(x); } else { y.getParent().setRight(x); //若是y是其父節點的右孩子,就設置y的父節點的右孩子爲x } x.setRight(y); //設置x的左孩子爲y y.setParent(x); //設置y的父親爲x } /** * 中序遍歷 * * @param treeNode 根節點 */ public static void inOrderTreeWalk(RBTreeNode<Integer> treeNode) { if (!NULL_NODE.equals(treeNode)) { inOrderTreeWalk(treeNode.getLeft()); System.out.print(treeNode.getValue() + " "); inOrderTreeWalk(treeNode.getRight()); } } /** * 前序遍歷 * * @param treeNode 根節點 */ public static void preOrderTreeWalk(RBTreeNode<Integer> treeNode) { if (treeNode != null && treeNode.getValue() != null) { System.out.print(treeNode.getValue() + " "); inOrderTreeWalk(treeNode.getLeft()); inOrderTreeWalk(treeNode.getRight()); } } /** * 後序遍歷 * * @param treeNode 根節點 */ public static void postOrderTreeWalk(RBTreeNode<Integer> treeNode) { if (!NULL_NODE.equals(treeNode)) { inOrderTreeWalk(treeNode.getLeft()); inOrderTreeWalk(treeNode.getRight()); System.out.print(treeNode.getValue() + " "); } } /** * 在樹中查詢指定值的節點 * * @param treeNode 樹的節點 * @param k 要查詢的值 * @return 若是查詢到節點的值等於要查詢的值,就返回這個節點,不然返回null */ public static RBTreeNode<Integer> treeSearch(RBTreeNode<Integer> treeNode, Integer k) { if (NULL_NODE.equals(treeNode) || treeNode.getValue() == k) { return treeNode; } if (k > treeNode.getValue()) { return treeSearch(treeNode.getRight(), k); } else { return treeSearch(treeNode.getLeft(), k); } } /** * 在樹中找到最大值 * * @param treeNode 樹的節點 * @return 若是查詢到節點的值等於要查詢的值,就返回這個節點,不然返回null */ public static RBTreeNode<Integer> treeMaximum(RBTreeNode<Integer> treeNode) { while (!NULL_NODE.equals(treeNode.getRight())) { treeNode = treeNode.getRight(); } return treeNode; } /** * 在樹中找到最小值 * * @param treeNode 樹的節點 * @return 若是查詢到節點的值等於要查詢的值,就返回這個節點,不然返回null */ public static RBTreeNode<Integer> treeMinimum(RBTreeNode<Integer> treeNode) { while (!NULL_NODE.equals(treeNode.getLeft())) { treeNode = treeNode.getLeft(); } return treeNode; } /** * 找一個節點的後繼 * * @return 一個節點的後繼 */ public static RBTreeNode<Integer> treeSuccessor(RBTreeNode<Integer> treeNode) { if (!NULL_NODE.equals(treeNode.getRight())) { return treeMinimum(treeNode.getRight()); } RBTreeNode<Integer> y = treeNode.getParent(); while (y != null && treeNode == y.getRight()) { treeNode = y; y = y.getParent(); } return y; } /** * 找一個節點的前驅 * * @return 一個節點的前驅 */ public static RBTreeNode<Integer> treePredecessor(RBTreeNode<Integer> treeNode) { if (!NULL_NODE.equals(treeNode.getLeft())) { return treeMaximum(treeNode.getLeft()); } RBTreeNode<Integer> y = treeNode.getParent(); while (y != null && treeNode == y.getLeft()) { treeNode = y; y = y.getParent(); } return y; } public static void transplant(RBTreeNode<Integer> root, RBTreeNode<Integer> target, RBTreeNode<Integer> source) { if (target.getParent() == null) { root.setValue(source.getValue()); root.setLeft(source.getLeft()); root.setRight(source.getRight()); root.setParent(source.getParent()); root.setColor(BLACK); } else if (target == target.getParent().getLeft()) { target.getParent().setLeft(source); } else { target.getParent().setRight(source); } source.setParent(target.getParent()); } /** * 從一棵樹中刪除一個節點 * * @param root 根節點 * @param z 要刪除的節點 */ public static void treeDelete(RBTreeNode<Integer> root, RBTreeNode<Integer> z) { RBTreeNode<Integer> y = z; // 記錄要刪除的節點 Boolean yOriginalColor = y.getColor(); // 記錄刪除節點的原來的顏色 RBTreeNode<Integer> x; // x是y的右孩子 if (NULL_NODE.equals(z.getLeft())) { // 若是z的左孩子爲空 x = z.getRight(); // 就把z的右孩子直接替換z transplant(root, z, z.getRight()); } else if (NULL_NODE.equals(z.getRight())) { // 若是z的右孩子爲空 x = z.getLeft(); // 就把z的左孩子直接替換z transplant(root, z, z.getLeft()); } else { y = treeMinimum(z.getRight()); // 若是z的兩個孩子都不爲空 就找到z的後繼t yOriginalColor = y.getColor(); // 從新記錄z的後繼y的顏色 x = y.getRight(); // 從新記錄y的右孩子 if (y.getParent() == z) { // 若是後繼y是z的孩子,就把y的右孩子的父親設爲y, x.setParent(y); // 其實這一步感受不必。x原本是y的右孩子,確定x的父親是y } else { // transplant(root, y, y.getRight()); // 先用y的右孩子替換y y.setRight(z.getRight()); // 把y的右孩子設爲z的右孩子 y.getRight().setParent(y); // 把y新的右孩子的父親設爲y } transplant(root, z, y); // 用y替換z y.setLeft(z.getLeft()); // 把y的左孩子設爲z的左孩子 y.getLeft().setParent(y); // 把y新的左孩子的父節點設爲y y.setColor(z.getColor()); // 把y的顏色設置爲z的顏色 } if (yOriginalColor == BLACK) { // 若是要刪除的節點的顏色是黑色的,就破壞了紅黑樹的 rbDeleteFixup(root, x); // 性質,須要進行修正 } } /** * 紅黑樹刪除後的修正 * * @param root 根節點 * @param x 刪除節點的右孩子 */ public static void rbDeleteFixup(RBTreeNode<Integer> root, RBTreeNode<Integer> x) { while (x != root && x.getColor() == BLACK) { if (x == x.getParent().getLeft()) { // 若是x是其父節點的左孩子 RBTreeNode<Integer> w = x.getParent().getRight(); // w是x的兄弟節點 if (w.getColor() == RED) { // case1 若是x的兄弟節點是紅色的 w.setColor(BLACK); // case1 設兄弟節點w的顏色爲黑色 x.getParent().setColor(RED); // case1 設x父節點的顏色爲紅色 leftRotate(root, x.getParent()); // case1 以x的父節點左旋 w = x.getParent().getRight(); // case1 從新設置x的兄弟節點w } if (w.getLeft().getColor() == BLACK && w.getRight().getColor() == BLACK) { // case2 若是兄弟節點w的左右孩子顏色都是黑色 w.setColor(RED); // case2 設兄弟節點w的顏色爲紅色 x = x.getParent(); // case2 設x的父節點爲當前節點 } else { if (w.getRight().getColor() == BLACK) { // case3 若是兄弟節點w的右孩子是黑色 w.getLeft().setColor(BLACK); // case3 設兄弟節點w的左孩子是黑色 w.setColor(RED); // case3 設兄弟節點w的顏色是紅色 rightRotate(root, w); // case3 右旋兄弟節點w w = x.getParent().getRight(); // case3 從新設置x的兄弟節點w } w.setColor(x.getParent().getColor()); // case4 設兄弟節點w的顏色是x的父節點的顏色 x.getParent().setColor(BLACK); // case4 設x的父節點的顏色爲黑色 w.getRight().setColor(BLACK); // case4 設兄弟節點w的右孩子顏色是黑色 leftRotate(root, x.getParent()); // case4 左旋x的父節點 x = root; } // 設x爲根節點 } else { // 若是x是其父節點的右孩子 RBTreeNode<Integer> w = x.getParent().getLeft(); // w是x的兄弟節點 if (w.getColor() == RED) { // case1 若是x的兄弟節點是紅色的 w.setColor(BLACK); // case1 設兄弟節點w的顏色爲黑色 x.getParent().setColor(RED); // case1 設x父節點的顏色爲紅色 rightRotate(root, x.getParent()); // case1 以x的父節點右旋 w = x.getParent().getLeft(); // case1 從新設置x的兄弟節點w } if (w.getLeft().getColor() == BLACK && w.getRight().getColor() == BLACK) { // case2 若是兄弟節點w的左右孩子顏色都是黑色 w.setColor(RED); // case2 設兄弟節點w的顏色爲紅色 x = x.getParent(); // case2 設x的父節點爲當前節點 } else { if (w.getLeft().getColor() == BLACK) { // case3 若是兄弟節點w的左孩子是黑色 w.getRight().setColor(BLACK); // case3 設兄弟節點w的右孩子是黑色 w.setColor(RED); // case3 設兄弟節點w的顏色是紅色 leftRotate(root, w); // case3 左旋兄弟節點w w = x.getParent().getLeft(); // case3 從新設置x的兄弟節點w } w.setColor(x.getParent().getColor()); // case4 設兄弟節點w的顏色是x的父節點的顏色 x.getParent().setColor(BLACK); // case4 設x的父節點的顏色爲黑色 w.getLeft().setColor(BLACK); // case4 設兄弟節點w的左孩子顏色是黑色 rightRotate(root, x.getParent()); // case4 右旋x的父節點 x = root; // 設x爲根節點 } } x.setColor(BLACK); } } }