返回

红黑树的正确用法,一次性掌握

见解分享

1. 红黑树简介
红黑树 (Red-Black Tree)是计算机科学中一种自平衡二叉查找树,它是对二叉查找树的一种改进,具有较好的搜索性能。红黑树与AVL树都是二叉排序树,但红黑树比AVL树具有更简单的实现和更好的效率。

2. 红黑树的性质

红黑树具有以下性质:

  1. 每个结点要么是红色,要么是黑色。
  2. 根结点是黑色。
  3. 每个叶结点是黑色。(叶结点是指没有子结点的结点。)
  4. 每个结点的两个子结点都是红色的。(称为连续红色性质)
  5. 从根结点到叶结点的路径上的黑色结点数量相同。(称为黑高相等性质)

3. 红黑树的操作

红黑树的操作与二叉排序树的操作类似,主要包括插入、删除和查找操作。

3.1 插入操作

红黑树的插入操作可以分为以下几个步骤:

  1. 将新结点插入到二叉排序树中,并将其颜色设置为红色。
  2. 如果新结点的父结点是红色,则执行修复操作。
  3. 修复操作包括以下几种情况:
    • 如果新结点的叔叔结点是红色,则将新结点、新结点的父结点和新结点的叔叔结点都染成黑色,并将其祖父结点染成红色。
    • 如果新结点的叔叔结点是黑色,则有两种情况:
      • 如果新结点是其父结点的右结点,则将新结点的父结点染成黑色,将新结点染成红色,并对其父结点进行右旋操作。
      • 如果新结点是其父结点的左结点,则将新结点的父结点染成黑色,将新结点染成红色,并对其父结点进行左旋操作。

3.2 删除操作

红黑树的删除操作可以分为以下几个步骤:

  1. 如果要删除的结点是红色,则将其直接删除。
  2. 如果要删除的结点是黑色,则将其转换为红色,并对其子树进行重新着色。
  3. 重新着色操作包括以下几种情况:
    • 如果要删除的结点的两个子结点都是黑色,则将其兄弟结点染成红色,并将其父结点染成黑色。
    • 如果要删除的结点的兄弟结点是红色,则将要删除的结点和其兄弟结点都染成黑色,并将其父结点染成红色。
    • 如果要删除的结点的兄弟结点是黑色,且其兄弟结点的两个子结点都是黑色,则将其兄弟结点的右结点染成红色,并对其兄弟结点进行左旋操作。
    • 如果要删除的结点的兄弟结点是黑色,且其兄弟结点的左子结点是红色,则将要删除的结点和其兄弟结点的左子结点都染成黑色,并将其兄弟结点染成红色,并对其兄弟结点进行右旋操作。

3.3 查找操作

红黑树的查找操作与二叉排序树的查找操作类似,通过不断与根结点比较,找到要查找的结点。

4. 红黑树的应用

红黑树由于其良好的搜索性能,被广泛应用于各种需要高效搜索的数据结构中,例如:

  • 数据库索引
  • 文件系统索引
  • 网络路由表
  • 编译器中的符号表

5. 红黑树的示例代码

以下是一个简单的红黑树的示例代码:

public class RedBlackTree {

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

    private Node root;

    private class Node {
        int key;
        Node left;
        Node right;
        boolean color;

        public Node(int key) {
            this.key = key;
            this.color = RED;
        }
    }

    public void insert(int key) {
        Node node = new Node(key);
        insert(node);
    }

    private void insert(Node node) {
        root = insert(node, root);
        root.color = BLACK;
    }

    private Node insert(Node node, Node parent) {
        if (parent == null) {
            return node;
        }

        if (node.key < parent.key) {
            parent.left = insert(node, parent.left);
        } else {
            parent.right = insert(node, parent.right);
        }

        if (isRed(parent.right) && !isRed(parent.left)) {
            parent = leftRotate(parent);
        }

        if (isRed(parent.left) && isRed(parent.left.left)) {
            parent = rightRotate(parent);
        }

        if (isRed(parent.left) && isRed(parent.right)) {
            flipColors(parent);
        }

        return parent;
    }

    public Node search(int key) {
        return search(key, root);
    }

    private Node search(int key, Node node) {
        if (node == null) {
            return null;
        }

        if (key == node.key) {
            return node;
        } else if (key < node.key) {
            return search(key, node.left);
        } else {
            return search(key, node.right);
        }
    }

    public void delete(int key) {
        delete(key, root);
    }

    private void delete(int key, Node node) {
        if (node == null) {
            return;
        }

        if (key < node.key) {
            delete(key, node.left);
        } else if (key > node.key) {
            delete(key, node.right);
        } else {
            if (node.left == null) {
                transplant(node, node.right);
            } else if (node.right == null) {
                transplant(node, node.left);
            } else {
                Node successor = findMin(node.right);
                node.key = successor.key;
                delete(successor.key, node.right);
            }
        }

        if (root != null) {
            root.color = BLACK;
        }
    }

    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;
        }

        if (v != null) {
            v.parent = u.parent;
        }
    }

    private Node findMin(Node node) {
        if (node == null) {
            return null;
        }

        while (node.left != null) {
            node = node.left;
        }

        return node;
    }

    private boolean isRed(Node node) {
        return node != null && node.color == RED;
    }

    private Node leftRotate(Node node) {
        Node right = node.right;
        node.right = right.left;
        if (right.left != null) {
            right.left.parent = node;
        }

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

        right.left = node;
        node.parent = right;

        return right;
    }

    private Node rightRotate(Node node) {
        Node left = node.left;
        node.left = left.right;
        if (left.right != null) {
            left.right.parent = node;
        }

        left.parent = node.parent;
        if (node.parent ==