背景

红黑树操作可视化平台

定义

(左根右)前提:二叉搜索树(左 < 根 < 右)
(根叶黑)根和叶子(NULL)都是黑色
(不红红)不存在连续的两个红色节点
(黑路同)任一节点到叶所有路径黑节点数量相同

性质:最长路径不超过最短路径的两倍
最长路径:一定是一黑一红一黑…一黑;最短路径顶多一黑一黑…一黑
运用:红黑树的运用比AVL树运用更广泛。HashMap、epoll…

插入

插入节点默认为红色。且只可能违反根叶黑或者不红红。

插入节点红黑树被破坏了存在三种情况:

  • 插入节点是根节点(破坏了根叶黑) ——> 直接变黑
  • 插入节点的叔叔是红色(破坏了不红红) ——> 叔父爷变色,爷爷变插入节点
  • 插入节点的叔叔是黑色(破坏了不红红) ——> (LL,RR,LR,RL)旋转,然后变色

构建

17 18 23 34 27 15 9 6 8 5 25

删除(难点)

AVL树删除三种场景:

  • 没有孩子——直接删除
  • 只有左子树/只有有右子树——直接代替
  • 左右子树都有——直接后继(或前驱)代替值,然后删除(转换成前两种情况)



红黑树(RBTree)及代码实现_插入节点

红黑树(RBTree)及代码实现_红黑树_02


双黑节点:所有经过它的路径都会少一个黑节点。

LL型

变色(r变s,s变p,p变黑)
右旋
双黑变单黑

p 7(黑)
     /        \
  s  5(黑)   双黑 d
   /        \
 r 2(黑)  6(红)

RR型

变色(r变s,s变p,p变黑)
左旋
双黑变单黑

p 5(黑)
     /          \
  d 双黑    7 (黑)  s
                 \
                12(红) r

LR型

变色(r变p,p变黑)
左旋左孩子,然后右旋
双黑变单黑

p 7(黑)
     /          \
  s 5(黑)   双黑 d
      \
    6(红) r

RL型

变色(r变p,p变黑)
右旋右孩子,然后左旋
双黑变单黑

p 6(黑)
     /          \
  d 双黑    12 (黑)  s
                /    
           8(红) r

红黑树删除案例

依次删除 13 37 27 17 34 9 10 23

代码实现(deepseek)

public class RBTree {

    private static final boolean RED = true;
    private static final boolean BLACK = false;

    class Node {
        int key;
        Node left, right, parent;
        boolean color;

        Node(int key) {
            this.key = key;
            this.color = RED; // 新节点默认为红色
            this.left = this.right = this.parent = null;
        }
    }

    private Node root;
    private final Node NIL; // 哨兵节点,代表空节点

    public RBTree() {
        NIL = new Node(-1);
        NIL.color = BLACK;
        root = NIL;
    }

    // 插入操作
    public void insert(int key) {
        Node newNode = new Node(key);
        newNode.left = NIL;
        newNode.right = NIL;

        Node parent = null;
        Node current = root;

        // 标准BST插入
        while (current != NIL) {
            parent = current;
            if (key < current.key) {
                current = current.left;
            } else if (key > current.key) {
                current = current.right;
            } else {
                return; // 重复键
            }
        }

        newNode.parent = parent;

        if (parent == null) {
            root = newNode;
        } else if (key < parent.key) {
            parent.left = newNode;
        } else {
            parent.right = newNode;
        }

        // 如果新节点是根节点,直接染黑
        if (newNode.parent == null) {
            newNode.color = BLACK;
            return;
        }

        // 如果祖父节点不存在,不需要修复
        if (newNode.parent.parent == null) {
            return;
        }

        // 修复红黑树性质
        fixInsert(newNode);
    }

    // 插入后修复
    private void fixInsert(Node node) {
        Node parent = node.parent;

        while (parent != null && parent.color == RED) {
            Node grandparent = parent.parent;

            if (parent == grandparent.left) {
                Node uncle = grandparent.right;

                // 情况1:叔叔节点是红色
                if (uncle.color == RED) {
                    parent.color = BLACK;
                    uncle.color = BLACK;
                    grandparent.color = RED;
                    node = grandparent;
                    parent = node.parent;
                } else {
                    // 情况2:节点是父节点的右孩子(LR情况)
                    if (node == parent.right) {
                        node = parent;
                        leftRotate(node);
                        parent = node.parent;
                    }

                    // 情况3:节点是父节点的左孩子(LL情况)
                    parent.color = BLACK;
                    grandparent.color = RED;
                    rightRotate(grandparent);
                }
            } else {
                // 对称情况:父节点是祖父节点的右孩子
                Node uncle = grandparent.left;

                // 情况1:叔叔节点是红色
                if (uncle.color == RED) {
                    parent.color = BLACK;
                    uncle.color = BLACK;
                    grandparent.color = RED;
                    node = grandparent;
                    parent = node.parent;
                } else {
                    // 情况2:节点是父节点的左孩子(RL情况)
                    if (node == parent.left) {
                        node = parent;
                        rightRotate(node);
                        parent = node.parent;
                    }

                    // 情况3:节点是父节点的右孩子(RR情况)
                    parent.color = BLACK;
                    grandparent.color = RED;
                    leftRotate(grandparent);
                }
            }

            if (node == root) {
                break;
            }
        }

        root.color = BLACK; // 确保根节点始终为黑色
    }

    // 左旋
    private void leftRotate(Node x) {
        Node y = x.right;
        x.right = y.left;

        if (y.left != NIL) {
            y.left.parent = x;
        }

        y.parent = x.parent;

        if (x.parent == null) {
            root = y;
        } else if (x == x.parent.left) {
            x.parent.left = y;
        } else {
            x.parent.right = y;
        }

        y.left = x;
        x.parent = y;
    }

    // 右旋
    private void rightRotate(Node y) {
        Node x = y.left;
        y.left = x.right;

        if (x.right != NIL) {
            x.right.parent = y;
        }

        x.parent = y.parent;

        if (y.parent == null) {
            root = x;
        } else if (y == y.parent.right) {
            y.parent.right = x;
        } else {
            y.parent.left = x;
        }

        x.right = y;
        y.parent = x;
    }

    // 删除操作
    public void delete(int key) {
        deleteNode(root, key);
    }

    private void deleteNode(Node node, int key) {
        Node z = NIL;
        Node x, y;

        // 查找要删除的节点
        while (node != NIL) {
            if (node.key == key) {
                z = node;
                break;
            } else if (key < node.key) {
                node = node.left;
            } else {
                node = node.right;
            }
        }

        if (z == NIL) {
            return; // 节点不存在
        }

        y = z;
        boolean yOriginalColor = y.color;

        if (z.left == NIL) {
            x = z.right;
            transplant(z, z.right);
        } else if (z.right == NIL) {
            x = z.left;
            transplant(z, z.left);
        } else {
            y = minimum(z.right);
            yOriginalColor = y.color;
            x = y.right;

            if (y.parent == z) {
                x.parent = y;
            } else {
                transplant(y, y.right);
                y.right = z.right;
                y.right.parent = y;
            }

            transplant(z, y);
            y.left = z.left;
            y.left.parent = y;
            y.color = z.color;
        }

        if (yOriginalColor == BLACK) {
            fixDelete(x);
        }
    }

    // 节点替换
    private void transplant(Node u, Node v) {
        if (u.parent == null) {
            root = v;
        } else if (u == u.parent.left) {
            u.parent.left = v;
        } else {
            u.parent.right = v;
        }
        v.parent = u.parent;
    }

    // 查找最小值节点
    private Node minimum(Node node) {
        while (node.left != NIL) {
            node = node.left;
        }
        return node;
    }

    // 删除后修复
    private void fixDelete(Node x) {
        while (x != root && x.color == BLACK) {
            if (x == x.parent.left) {
                Node w = x.parent.right;

                // 情况1:兄弟节点是红色
                if (w.color == RED) {
                    w.color = BLACK;
                    x.parent.color = RED;
                    leftRotate(x.parent);
                    w = x.parent.right;
                }

                // 情况2:兄弟节点的两个子节点都是黑色
                if (w.left.color == BLACK && w.right.color == BLACK) {
                    w.color = RED;
                    x = x.parent;
                } else {
                    // 情况3:兄弟节点的右子节点是黑色,左子节点是红色
                    if (w.right.color == BLACK) {
                        w.left.color = BLACK;
                        w.color = RED;
                        rightRotate(w);
                        w = x.parent.right;
                    }

                    // 情况4:兄弟节点的右子节点是红色
                    w.color = x.parent.color;
                    x.parent.color = BLACK;
                    w.right.color = BLACK;
                    leftRotate(x.parent);
                    x = root;
                }
            } else {
                // 对称情况
                Node w = x.parent.left;

                if (w.color == RED) {
                    w.color = BLACK;
                    x.parent.color = RED;
                    rightRotate(x.parent);
                    w = x.parent.left;
                }

                if (w.right.color == BLACK && w.left.color == BLACK) {
                    w.color = RED;
                    x = x.parent;
                } else {
                    if (w.left.color == BLACK) {
                        w.right.color = BLACK;
                        w.color = RED;
                        leftRotate(w);
                        w = x.parent.left;
                    }

                    w.color = x.parent.color;
                    x.parent.color = BLACK;
                    w.left.color = BLACK;
                    rightRotate(x.parent);
                    x = root;
                }
            }
        }

        x.color = BLACK;
    }

    // 中序遍历
    public void inOrder() {
        inOrder(root);
        System.out.println();
    }

    private void inOrder(Node node) {
        if (node != NIL) {
            inOrder(node.left);
            System.out.print(node.key + "(" + (node.color == RED ? "R" : "B") + ") ");
            inOrder(node.right);
        }
    }

    // 测试代码
    public static void main(String[] args) {
        RBTree tree = new RBTree();

        int[] values = {7, 3, 18, 10, 22, 8, 11, 26, 2, 6, 13};

        System.out.println("插入顺序: " + java.util.Arrays.toString(values));
        for (int value : values) {
            tree.insert(value);
        }

        System.out.println("中序遍历:");
        tree.inOrder();

        System.out.println("删除节点: 18");
        tree.delete(18);

        System.out.println("删除后的中序遍历:");
        tree.inOrder();
    }
}

运行结果:

插入顺序: [7, 3, 18, 10, 22, 8, 11, 26, 2, 6, 13]
中序遍历:
2(R) 3(B) 6(R) 7(R) 8(B) 10(B) 11(B) 13(R) 18(R) 22(B) 26(R) 
删除节点: 18
删除后的中序遍历:
2(R) 3(B) 6(R) 7(R) 8(B) 10(B) 11(B) 13(R) 22(R) 26(B)

参考