手撕红黑树
1. 红黑树的性值
1.1 平衡条件

- 每个节点非黑即红
- 根节点是黑色
- 叶节点(NIL)是黑色
- 如果一个节点是红色,则它的两个子节点都是黑色
- 从任意节点出发到所有叶节点路径上,黑色节点数量相同
1.2最长路径和最短路径长度关系?
根据平衡条件第4、5点,最短路径都是黑色;最长路径红黑相间;最长是最短的两倍;
1.3平衡调整的终极法门
插入调整站在祖父节点看
删除调整站在父节点看
插入和删除的情况处理一共五种
1.4新插入的节点的颜色
红色,因为插入黑色会引发失衡;插入红色不一定会失衡。
2. 红黑树的插入
2.1 调整原则
为了不影响整颗树的平衡, 调整前路径上的黑节点数量等于调整后路径上黑色节点数量
2.2 调整目的
消除双红
2.3 调整方法
情况一:uncle为红色
站在15节点向下看,发现右子树为红色,并且右子树有一个红色的子节点 ==》 失衡

调整方法:
- 
15节点 ==》 变红 
- 
1节点 ==》 变黑 
- 
20节点 ==》 变黑 
情况二:uncle为黑色
站在20节点向下看,左侧节点为红色,并且左侧节点的孩子有红色节点 ==》失衡

类似于AVL树的LL失衡调整 ==> 右旋

调整后的变色方案可以选择红色上浮或下沉
红色上浮:

红色下沉:

3. 红黑树的删除
3.1 删除场景
- 
场景1: 删除度为0的红色节点: 直接删除即可,不会引发失衡 
  
- 
场景2:删除度为1的红色节点:不存在这样的节点 
若一个红色节点下面有子节点,一定同时有两个黑色子节点
原因:红黑树的第4条和第5条性值
性值4: 如果一个节点是红色,则它的两个子节点都是黑色
性值5: 从任一节点出发到所有叶节点路径上,黑色节点数量相同
-  场景3(需要调整): 删除度为0的黑色节点
  
删除X后,因X度为0,其下只有NIL节点;
红色根节点左子树一共两个黑色节点(包含NIL节点);所以该红色根节点右子树也需要有两个黑色节点 ==>
即,将该度为0 的黑色节点的颜色加到NIL节点上,至此,这个NIL节点变为双重黑
删除调整的目的就是为了消除双重黑节点。
-  场景4: 删除度为1的黑色节点
 度为1的黑色节点的唯一子孩子一定是红色的,如下图所示:
  
 删除X,将唯一子节点挂到父节点,将当前节点X的黑色加到唯一子孩子上。
3.2 调整场景
场景3中,删除度为0的黑色节点会引发红黑树的失衡,消除的双重黑。
-  情况一 (双重黑的兄弟节点为黑色)
 双重黑X的兄弟为黑,且兄弟节点的子节点均为黑色节点:
  
调整方法:
- 
双重黑 及 其兄弟节点 --> 去掉一重黑 
- 
双重黑的父节点 --> 加一重黑 
- 
情况二 RR失衡:双重黑的兄弟节点为黑色, 右子树的右子树为红色: 
 双重黑为左子树,双重黑的兄弟节点的右子树为确定性红色(左子树颜色不确定)
  
 若38为红色,则调整前左子树一共有2个黑,则调整后,仍需要为两个黑: 将51改为黑,38 & 72改为红;
 若38为黑色,则调整前左子树一共3个黑,调整后,仍需要为3个黑,将72改为黑。
 总结RR失衡调整策略:大左旋 => 2个子节点改为黑色,一个新根改为原根的颜色。
- 
情况三RL失衡:双重黑的兄弟节点为黑色,右子树的左子树为红色,右子树为黑色 
 双重黑为左子树,双重黑的兄弟节点的左子树为红色,右子树为确定性黑色(一旦右子树为红,则为RR失衡)
  
 调整方法:
 step1: 小右旋 => 将原根节点的颜色和新根节点的颜色对调(原根72改为红色,新根51改为黑色),变为情况二,图示 =》
  
step2: 大左旋,即,调整为 =》

将新根(51)变为原根(38)的颜色
将新根(51)左右子树变为黑色
双重黑变为黑色
-  情况四: (双重黑的兄弟节点为红色):
 step1: 根节点改为红色
step2: 情况(1)若 => 双重黑为右子树,根节点的左子树为红色:将该根节点右旋
            情况(2)若 => 双重黑为左子树,根节点的右子树为红色:将该根节点左旋
step3: 新根(原红色的兄弟节点)改为黑色
step4: 情况(1)=> 递归到右子树
            情况(2)=> 递归到左子树
下面图演示了 ==> 若双重黑为左子树,根节点的右子树为红色的情况

左旋 =》新根节点改为黑色,原根节点(双重黑的父节点)改为红色

至此,双重黑X节点的兄弟节点变为黑色,应递归到当前根节点的左子树中继续调整,该调整已经转换为上面的双重黑的兄弟节点为黑色的情况处理
代码:
public class RbTree {
    static Node NIL = new Node(0, 1, null, null);
    static class Node {
        int key;
        int color;//0:red; 1:black; 2:double black
        Node left;
        Node right;
        Node(int key, int color, Node left, Node right) {
            this.key = key;
            this.color = color;
            this.left = left;
            this.right = right;
        }
        Node(int key, int color) {
            this.key = key;
            this.color = color;
            this.left = NIL;
            this.right = NIL;
        }
    }
    Node getNewNode(int key) {
        return new Node(key, 0);
    }
    private Node _insert(Node root, int key) {
        if (root == NIL) return getNewNode(key);
        if (root.key == key) return root;
        if (key < root.key) {
            root.left = _insert(root.left, key);
        } else {
            root.right = _insert(root.right, key);
        }
        return insert_maintain(root);
    }
    private boolean has_red_child(Node root) {
        return root.left.color == 0 || root.right.color == 0;
    }
    private Node insert_maintain(Node root) {
        int flag = 0;
        if (root.left.color == 0 && has_red_child(root.left)) {
            flag = 1;
        }
        if (root.right.color == 0 && has_red_child(root.right)) {
            flag = 2;
        }
        if (flag == 0) {
            return root;
        }
        if (root.left.color == 0 && root.right.color == 0) {
            root.color = 0;
            root.left.color = 1;
            root.right.color = 1;
            return root;
        }
        if (flag == 1) {
            if (root.left.right.color == 0) {
                root.left = left_rotate(root.left);
            }
            root = right_rotate(root);
        } else {
            if (root.right.left.color == 0) {
                root.right = right_rotate(root.right);
            }
            root = left_rotate(root);
        }
        root.color = 0;
        root.left.color = 1;
        root.right.color = 1;
        return root;
    }
    private Node right_rotate(Node root) {
        Node temp = root.left;
        root.left = temp.right;
        temp.right = root;
        return temp;
    }
    private Node left_rotate(Node root) {
        Node temp = root.right;
        root.right = temp.left;
        temp.left = root;
        return temp;
    }
    Node insert(Node root, int key) {
        root = _insert(root, key);
        root.color = 1;
        return root;
    }
    Node _erase(Node root, int key) {
        if (root == null) return root;
        if (key < root.key) {
            root.left = _erase(root.left, key);
        } else if (key > root.key) {
            root.right = _erase(root.right, key);
        } else {
            if (root.left == NIL || root.right == NIL) {
                Node temp = root.left == NIL ? root.right : root.left;
                temp.color += root.color;
                return temp;
            } else {
                Node temp = predecessor(root);
                root.key = temp.key;
                root.left = _erase(root.left, temp.key);
            }
        }
        return erase_maintain(root);
    }
    private Node erase_maintain(Node root) {
        if (root.right.color != 2 && root.left.color != 2) return root;
        //情况四: 双重黑的兄弟节点为红色
        if (has_red_child(root)) {
            int flag = 0;
            root.color = 0;
            if (root.right.color == 0) {
                root = left_rotate(root);
                flag = 1;
            } else {
                root = right_rotate(root);
                flag = 2;
            }
            root.color = 1;
            if (flag == 1) {
                root.left = erase_maintain(root.left);
            } else {
                root.right = erase_maintain(root.right);
            }
            return root;
        }
        //情况一:双重黑的兄弟节点为黑色,且该兄弟节点下无红色节点
        if (root.left.color == 1 && !has_red_child(root.right) || root.right.color == 1 && !has_red_child(root.left)) {
            root.left.color -= 1;
            root.right.color -= 1;
            root.color += 1;
            return root;
        }
        //情况二 & 三:双重黑的兄弟节点为黑色,且该兄弟节点下存在红色节点
        if (root.left.color == 1) {//双重黑为右子树
            root.right.color = 1;//将双重黑节点变为黑色
            //若左子树的左子树为红色 ==> LL失衡
            //否则(若左子树的右子树为黑色,即,红色节点位于左子树的左子树) ==> LR失衡
            if (root.left.left.color != 0) {
                root.left.color = 0;//将左子树原根变红
                root.left = left_rotate(root.left);//将左子树左旋
                root.left.color = 1;//将左子树新根变黑
            }
            root.left.color = root.color;//将左子树小右旋后,将左子树的新根变为原根颜色
            root = right_rotate(root);//将根大右旋
        } else {//双重黑为左子树
            root.left.color = 1;//将双重黑节点变为黑色
            //若右子树的右子树为红色 ==> RR失衡
            //否则(右子树的右子树为黑色,即,红色节点为右子树的左子树) ==> RL失衡
            if (root.right.right.color != 0) {
                root.right.color = 0;//将右子树原根变红
                root.right = right_rotate(root.right);
                root.right.color = 1;//将右子树新根变黑
            }
            root.right.color = root.color;//将右子树小左旋后,将右子树中新的根节点的颜色变为原根节点的颜色
            root = left_rotate(root);//将根大左旋
        }
        //将新根节点的左右子树变为黑色
        root.right.color = 1;
        root.left.color = 1;
        return root;
    }
    private Node predecessor(Node root) {
        Node temp = root.left;
        while (temp.right != NIL) {
            temp = temp.right;
        }
        return temp;
    }
    Node erase(Node root, int key) {
        root = _erase(root, key);
        root.color = 1;
        return root;
    }
    static void outPut(Node root) {
        if (root == NIL) return;
        System.out.println(root.color + ", " + root.key + ", " + root.left.key + ", " + root.right.key);
        outPut(root.left);
        outPut(root.right);
    }
    public static void main(String[] args) {
        RbTree rbTree = new RbTree();
        Node root = NIL;
        Scanner scanner = new Scanner(System.in);
        System.out.println("Enter array: ");
        while (true) {
            String[] strings = scanner.nextLine().split(", ");
            for (String string : strings) {
                int key = Integer.parseInt(string);
                root = rbTree.insert(root, key);
                System.out.println("--------AVL tree print-------");
                outPut(root);
                System.out.println();
                System.out.println("--------AVL tree print done -------");
            }
        }
    }
}
测试结果:
Enter array: 
1, 2, 3, 4, 5, 6, 7, 8, 9
--------AVL tree print-------
1, 1, 0, 0
--------AVL tree print done -------
--------AVL tree print-------
1, 1, 0, 2
0, 2, 0, 0
--------AVL tree print done -------
--------AVL tree print-------
1, 2, 1, 3
1, 1, 0, 0
1, 3, 0, 0
--------AVL tree print done -------
--------AVL tree print-------
1, 2, 1, 3
1, 1, 0, 0
1, 3, 0, 4
0, 4, 0, 0
--------AVL tree print done -------
--------AVL tree print-------
1, 2, 1, 4
1, 1, 0, 0
0, 4, 3, 5
1, 3, 0, 0
1, 5, 0, 0
--------AVL tree print done -------
--------AVL tree print-------
1, 2, 1, 4
1, 1, 0, 0
0, 4, 3, 5
1, 3, 0, 0
1, 5, 0, 6
0, 6, 0, 0
--------AVL tree print done -------
--------AVL tree print-------
1, 4, 2, 6
1, 2, 1, 3
1, 1, 0, 0
1, 3, 0, 0
1, 6, 5, 7
1, 5, 0, 0
1, 7, 0, 0
--------AVL tree print done -------
--------AVL tree print-------
1, 4, 2, 6
1, 2, 1, 3
1, 1, 0, 0
1, 3, 0, 0
1, 6, 5, 7
1, 5, 0, 0
1, 7, 0, 8
0, 8, 0, 0
--------AVL tree print done -------
--------AVL tree print-------
1, 4, 2, 6
1, 2, 1, 3
1, 1, 0, 0
1, 3, 0, 0
1, 6, 5, 8
1, 5, 0, 0
0, 8, 7, 9
1, 7, 0, 0
1, 9, 0, 0
--------AVL tree print done -------
 
                   
                   
                   
                   
                             
       
           
                 
                 
                 
                 
                 
                
               
                 
                 
                 
                 
                
               
                 
                 扫一扫
扫一扫
                     
              
             
                   1209
					1209
					
 被折叠的  条评论
		 为什么被折叠?
被折叠的  条评论
		 为什么被折叠?
		 
		  到【灌水乐园】发言
到【灌水乐园】发言                                
		 
		 
    
   
    
   
             
            


 
            