返回

深入了解红黑树:数据结构中的优雅平衡

闲谈

红黑树:平衡的艺术

数据结构的有效性取决于其组织和管理数据的能力。红黑树就是这样的结构,它通过引入了额外的平衡限制,在二叉搜索树的基础上更进一步。这些限制确保了树在插入、删除或搜索操作后始终保持近似平衡,从而实现了卓越的性能。

红黑树的特性

红黑树的关键特性如下:

  • 每个节点要么是红色,要么是黑色。
  • 根节点是黑色。
  • 每个叶子节点(NULL)是黑色。
  • 每个红色结点的两个子结点一定都是黑色。
  • 任意一结点到每个叶子节点的路径上的黑色节点数目相同。

红黑树的优势

平衡特性赋予了红黑树以下优势:

  • 快速查找: 由于红黑树近似平衡,查找操作的复杂度通常为 O(log n),确保了快速数据检索。
  • 高效插入: 与普通二叉搜索树不同,红黑树通过旋转和重新着色操作在插入新节点时保持平衡,避免了树的退化。
  • 稳定删除: 删除操作同样高效,红黑树通过重新着色和旋转来维持平衡,确保删除操作后仍保持近似平衡。

代码示例

为了更好地理解红黑树的运作原理,让我们通过一个代码示例来演示其基本操作。以下 Java 代码实现了红黑树的数据结构:

class RedBlackTree<T extends Comparable<T>> {

    private Node<T> root;

    // 节点颜色枚举
    private enum Color {
        RED, BLACK
    }

    // 节点类
    private class Node<T> {
        T data;
        Color color;
        Node<T> left;
        Node<T> right;

        public Node(T data) {
            this.data = data;
            this.color = Color.RED;
        }
    }

    // 插入操作
    public void insert(T data) {
        Node<T> newNode = new Node<>(data);
        insert(newNode);
    }

    private void insert(Node<T> node) {
        if (root == null) {
            root = node;
        } else {
            Node<T> parent = null;
            Node<T> current = root;
            while (current != null) {
                parent = current;
                if (node.data.compareTo(current.data) < 0) {
                    current = current.left;
                } else {
                    current = current.right;
                }
            }

            if (node.data.compareTo(parent.data) < 0) {
                parent.left = node;
            } else {
                parent.right = node;
            }
            fixInsert(node);
        }
    }

    // 修复插入后破坏的红黑树特性
    private void fixInsert(Node<T> node) {
        while (node != root && node.color == Color.RED && node.parent.color == Color.RED) {
            Node<T> uncle = node.parent.sibling();

            if (uncle != null && uncle.color == Color.RED) {
                node.parent.color = Color.BLACK;
                uncle.color = Color.BLACK;
                node.parent.parent.color = Color.RED;
                node = node.parent.parent;
            } else {
                if (node == node.parent.right && node.parent == node.parent.parent.left) {
                    rotateLeft(node.parent);
                    node = node.left;
                } else if (node == node.parent.left && node.parent == node.parent.parent.right) {
                    rotateRight(node.parent);
                    node = node.right;
                }

                node.parent.color = Color.BLACK;
                node.parent.parent.color = Color.RED;
                if (node == node.parent.left) {
                    rotateRight(node.parent.parent);
                } else {
                    rotateLeft(node.parent.parent);
                }
            }
        }

        root.color = Color.BLACK;
    }

    // 删除操作
    public void delete(T data) {
        if (root == null) {
            return;
        }

        Node<T> node = root;
        while (node != null) {
            if (data.compareTo(node.data) < 0) {
                node = node.left;
            } else if (data.compareTo(node.data) > 0) {
                node = node.right;
            } else {
                delete(node);
                return;
            }
        }
    }

    private void delete(Node<T> node) {
        if (node.left == null && node.right == null) {
            if (node == root) {
                root = null;
            } else {
                if (node.parent.left == node) {
                    node.parent.left = null;
                } else {
                    node.parent.right = null;
                }
            }
        } else if (node.left == null) {
            if (node == root) {
                root = node.right;
            } else {
                if (node.parent.left == node) {
                    node.parent.left = node.right;
                } else {
                    node.parent.right = node.right;
                }
                node.right.parent = node.parent;
            }
        } else if (node.right == null) {
            if (node == root) {
                root = node.left;
            } else {
                if (node.parent.left == node) {
                    node.parent.left = node.left;
                } else {
                    node.parent.right = node.left;
                }
                node.left.parent = node.parent;
            }
        } else {
            Node<T> successor = findSuccessor(node);
            node.data = successor.data;
            delete(successor);
        }

        fixDelete(node);
    }

    // 修复删除后破坏的红黑树特性
    private void fixDelete(Node<T> node) {
        while (node != root && node.color == Color.BLACK) {
            Node<T> sibling = node.sibling();

            if (sibling.color == Color.RED) {
                sibling.color = Color.BLACK;
                node.parent.color = Color.RED;
                if (node == node.parent.left) {
                    rotateLeft(node.parent);
                } else {
                    rotateRight(node.parent);
                }
            } else {
                if (sibling.left != null && sibling.left.color == Color.RED) {
                    sibling.left.color = Color.BLACK;
                    sibling.color = Color.RED;
                    rotateRight(sibling);
                } else if (sibling.right != null && sibling.right.color == Color.RED) {
                    sibling.right.color = Color.BLACK;
                    sibling.color = Color.RED;
                    rotateLeft(sibling);
                } else {
                    sibling.color = Color.RED;
                    if (node == node.parent.left) {
                        rotateRight(node.parent);
                    } else {
                        rotateLeft(node.parent);
                    }
                    break;
                }
            }
        }

        node.color = Color.BLACK;
        root.color = Color.BLACK;
    }

    // 查找后继节点
    private Node<T> findSuccessor(Node<T> node) {
        Node<T> successor = node.right;
        while (successor.left != null) {
            successor = successor.left;
        }
        return successor;
    }

    // 左旋操作
    private void rotateLeft(Node<T> node) {
        Node<T> 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;