红黑树的一些理解

红黑树是一种自平衡的二叉查找树,它在每个节点上增加了一个额外的属性表示节点的颜色,可以是红色或黑色。通过满足一定的性质,红黑树确保了在进行插入、删除等操作时,树的高度保持在对数级别,从而保证了操作的时间复杂度为 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) 级别。
  • 红色性质 则是为了防止出现连续的红色节点,这样可以避免了路径上出现两个相邻的红色节点,保证了在插入、删除等操作后的平衡性。

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

相关推荐
j7~几秒前
【Python】(篇七)《使用Python库》 -- 详解
开发语言·后端·python·编程学习·python标准库·python第三方库·python拓展
Memory_荒年7 分钟前
订单超时未支付?从“定时扫库”一步步到最终形态
java·后端
多多爱学习16 分钟前
括号有几层?得看还有多少个左括号没闭合
c语言·c++·算法·面试
续写烂尾31 分钟前
MK SD NAND(贴片式TF卡)替代Nor Flash:1Gb容量与256Mb Nor
算法·microsoft
u0111026751 小时前
图片预览越来越占内存聊聊 URL.createObjectURL 的释放时机
图像处理·深度学习·算法·ai作画
Zane19941 小时前
同样是遍历图,为什么BFS能保证找到最短路径,DFS却不行
算法
无限码力1 小时前
2026华为OD机试真题 新系统 9月27日【坚果巧克力】
算法·华为od·华为od机考·华为od机试真题·华为od机试·华为od机考真题题解·华为社招笔试真题
samforce1 小时前
叹息之墙——人类认知 AI,终将遇到的一堵同构之墙
人工智能·深度学习·算法·哲学·认知科学
卷无止境1 小时前
便宜模型和贵模型到底差在哪儿?一份关于Claude与GPT分级体系的深度梳理
后端·python
l1t1 小时前
编译测试兼容gzip并行压缩解压工具pigz
c++·算法