红黑树简介

     红黑树是一种搜索二叉树,而且也是一种平衡搜索二叉树,它可以保证在最坏的情况下的基本的操作的时间复杂度为O(lgn)。

  红黑树具有如下的性质:

  1. 每个节点要么是红色的,要不是黑色的。
  2. 根节点是黑色的
  3. 每个叶节点(NIL)是黑色的
  4. 如果一个结点是红色的,则它的两个子结点是黑色的。
  5. 对每个节点,从该节点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点。

红黑树的旋转

  注意这个旋转和AVL树的旋转不一样,红黑树的旋转只有左旋和右旋。那为什么要旋转呢,因为是在插入和删除节点后,这棵树可能就不满足红黑树的性质了,所以需要做一些重新着色和旋转的操作。

 

下面看一下左旋和右旋的示意图。

左旋可以理解为,以那个节点左旋的,这个节点就会成为自己右孩子的左孩子。

右旋可以理解为,以那个节点右旋的,这个节点就会成为自己左孩子的右孩子。

 

 

下面是左旋的伪代码 假设 x.right !=T.nil 且根结点的父结点为T.nil

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的父亲

右旋的伪代码

 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的父亲 

 

 

红黑树的插入

红黑树的插入前面的逻辑和普通的二叉搜索树的插入逻辑差不多。这里不再多说,主要差别在于插入后可能会破坏红黑树的性质。我们主要来看看修复的伪代码。

先把要插入节点设为红色,为什么设为红色而不是黑色呢,这个可以先看一下红黑树的性质,如果把插入节点设置黑色,那么性质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);
        }
    }
}

 

posted @ 2017-11-26 19:23  dupang  阅读(416)  评论(0编辑  收藏  举报