紅黑樹簡介

     紅黑樹是一種搜索二叉樹,並且也是一種平衡搜索二叉樹,它能夠保證在最壞的狀況下的基本的操做的時間複雜度爲O(lgn)。ide

  紅黑樹具備以下的性質:post

  1. 每一個節點要麼是紅色的,要不是黑色的。
  2. 根節點是黑色的
  3. 每一個葉節點(NIL)是黑色的
  4. 若是一個結點是紅色的,則它的兩個子結點是黑色的。
  5. 對每一個節點,從該節點到其全部後代葉結點的簡單路徑上,均包含相同數目的黑色結點。

紅黑樹的旋轉測試

  注意這個旋轉和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);
        }
    }
}
相關文章
相關標籤/搜索