红黑树的一些理解

红黑树是一种自平衡的二叉查找树,它在每个节点上增加了一个额外的属性表示节点的颜色,可以是红色或黑色。通过满足一定的性质,红黑树确保了在进行插入、删除等操作时,树的高度保持在对数级别,从而保证了操作的时间复杂度为 O(log n)。

红黑树满足以下性质:

  1. 每个节点是红色或黑色。
  2. 根节点是黑色。
  3. 每个叶子节点(NIL节点,空节点)是黑色的。
  4. 如果一个节点是红色的,则它的两个子节点都是黑色的(不能有两个相连的红色节点)。
  5. 从任一节点到其每个叶子节点的所有路径都包含相同数目的黑色节点(黑色节点数量相同)。

这里是一个简单的红黑树的 Java 实现,包含插入操作:

java 复制代码
class RedBlackTreeNode {
    int data;
    RedBlackTreeNode parent;
    RedBlackTreeNode left;
    RedBlackTreeNode right;
    int color;

    public RedBlackTreeNode(int data) {
        this.data = data;
        color = 1; // 新插入的节点默认为红色
        parent = left = right = null;
    }
}

public class RedBlackTree {
    private RedBlackTreeNode root;

    // 左旋
    private void leftRotate(RedBlackTreeNode x) {
        RedBlackTreeNode y = x.right;
        x.right = y.left;
        if (y.left != null)
            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(RedBlackTreeNode y) {
        RedBlackTreeNode x = y.left;
        y.left = x.right;
        if (x.right != null)
            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 insert(int data) {
        RedBlackTreeNode newNode = new RedBlackTreeNode(data);
        RedBlackTreeNode parent = null;
        RedBlackTreeNode current = root;
        while (current != null) {
            parent = current;
            if (newNode.data < current.data)
                current = current.left;
            else
                current = current.right;
        }
        newNode.parent = parent;
        if (parent == null)
            root = newNode;
        else if (newNode.data < parent.data)
            parent.left = newNode;
        else
            parent.right = newNode;
        newNode.color = 1; // 新插入的节点默认为红色
        fixInsert(newNode);
    }

    // 插入后修复红黑树性质
    private void fixInsert(RedBlackTreeNode k) {
        RedBlackTreeNode u;
        while (k.parent.color == 1) {
            if (k.parent == k.parent.parent.right) {
                u = k.parent.parent.left;
                if (u.color == 1) {
                    u.color = 0;
                    k.parent.color = 0;
                    k.parent.parent.color = 1;
                    k = k.parent.parent;
                } else {
                    if (k == k.parent.left) {
                        k = k.parent;
                        rightRotate(k);
                    }
                    k.parent.color = 0;
                    k.parent.parent.color = 1;
                    leftRotate(k.parent.parent);
                }
            } else {
                u = k.parent.parent.right;

                if (u.color == 1) {
                    u.color = 0;
                    k.parent.color = 0;
                    k.parent.parent.color = 1;
                    k = k.parent.parent;
                } else {
                    if (k == k.parent.right) {
                        k = k.parent;
                        leftRotate(k);
                    }
                    k.parent.color = 0;
                    k.parent.parent.color = 1;
                    rightRotate(k.parent.parent);
                }
            }
            if (k == root) {
                break;
            }
        }
        root.color = 0;
    }

    // 中序遍历
    private void inorder(RedBlackTreeNode root) {
        if (root == null)
            return;
        inorder(root.left);
        System.out.print(root.data + " ");
        inorder(root.right);
    }

    public void inorder() {
        inorder(root);
    }

    public static void main(String[] args) {
        RedBlackTree tree = new RedBlackTree();
        tree.insert(10);
        tree.insert(20);
        tree.insert(30);
        tree.insert(40);
        tree.insert(50);
        tree.insert(60);
        tree.insert(70);

        System.out.println("红黑树中序遍历:");
        tree.inorder();
    }
}

这个实现中,左旋和右旋操作用于保持红黑树的性质。在插入操作中,先将新插入的节点标记为红色,然后通过 fixInsert() 方法来修复可能违反红黑树性质的地方。

让我们逐个讲解代码中的每个方法:

  1. RedBlackTreeNode 类:

    • 定义了红黑树节点的结构。
    • 每个节点包含 data(节点的值)、parent(父节点的引用)、left(左子节点的引用)、right(右子节点的引用)、color(节点的颜色,0 表示黑色,1 表示红色)。
  2. RedBlackTree 类:

    • root:红黑树的根节点。
  3. leftRotate(RedBlackTreeNode x) 方法:

    • 实现了左旋操作。
    • 参数 x 是要进行左旋的节点。
    • x 的右子节点 y 上移为 x 的父节点,x 成为 y 的左子节点。
    • 旋转后要更新节点的父节点引用。
  4. rightRotate(RedBlackTreeNode y) 方法:

    • 实现了右旋操作。
    • 参数 y 是要进行右旋的节点。
    • y 的左子节点 x 上移为 y 的父节点,y 成为 x 的右子节点。
    • 旋转后要更新节点的父节点引用。
  5. insert(int data) 方法:

    • 插入新节点到红黑树中。
    • 首先创建一个新节点,并按照二叉查找树的规则找到其应该插入的位置。
    • 将新节点插入,并将其颜色标记为红色。
    • 调用 fixInsert() 方法修正红黑树的性质。
  6. fixInsert(RedBlackTreeNode k) 方法:

    • 修复插入节点后可能违反红黑树性质的问题。
    • 参数 k 是刚刚插入的节点。
    • 通过对 k 的父节点、叔节点和祖父节点的颜色进行判断和旋转操作来保持红黑树的性质。
  7. inorder(RedBlackTreeNode root) 方法:

    • 中序遍历红黑树。
    • 递归地从左子树开始遍历,然后访问当前节点,最后递归地遍历右子树。
  8. inorder() 方法:

    • 对外提供的中序遍历方法的入口点。
  9. main(String[] args) 方法:

    • 测试主方法,创建一个红黑树对象,并插入一些节点,然后进行中序遍历以验证红黑树的正确性。

这些方法共同构成了一个简单的红黑树的实现,通过这些方法可以实现对红黑树的插入操作,并保持其性质。

红黑树通过保持以下两个性质来维持平衡:

  1. 黑色平衡性(Black-Height Balance):确保从根到叶子的每条路径上的黑色节点数目相同。换句话说,红黑树保证了所有路径上的黑色节点数目相等,这样就能够保证树的高度不会过高。

  2. 红色性质(Red Property):保证没有两个相邻的红色节点,也就是说,红色节点不能出现相连的情况。

这两个性质的作用如下:

  • 黑色平衡性 确保了红黑树的高度不会过高,使得其插入、删除等操作的时间复杂度保持在 O(log n) 级别。
  • 红色性质 则是为了防止出现连续的红色节点,这样可以避免了路径上出现两个相邻的红色节点,保证了在插入、删除等操作后的平衡性。

综合这两个性质,红黑树能够保持平衡,并且在动态插入、删除节点时,通过旋转和重新着色等操作来维护这些性质,从而保持树的平衡性。

相关推荐
hsling松子2 小时前
使用PaddleHub智能生成,献上浓情国庆福
人工智能·算法·机器学习·语言模型·paddlepaddle
dengqingrui1233 小时前
【树形DP】AT_dp_p Independent Set 题解
c++·学习·算法·深度优先·图论·dp
C++忠实粉丝3 小时前
前缀和(8)_矩阵区域和
数据结构·c++·线性代数·算法·矩阵
ZZZ_O^O3 小时前
二分查找算法——寻找旋转排序数组中的最小值&点名
数据结构·c++·学习·算法·二叉树
CV-King4 小时前
opencv实战项目(三十):使用傅里叶变换进行图像边缘检测
人工智能·opencv·算法·计算机视觉
2401_857622664 小时前
SpringBoot框架下校园资料库的构建与优化
spring boot·后端·php
代码雕刻家4 小时前
数据结构-3.9.栈在递归中的应用
c语言·数据结构·算法
雨中rain4 小时前
算法 | 位运算(哈希思想)
算法
2402_857589364 小时前
“衣依”服装销售平台:Spring Boot框架的设计与实现
java·spring boot·后端
哎呦没6 小时前
大学生就业招聘:Spring Boot系统的架构分析
java·spring boot·后端