Java随笔-红黑树

红黑树(Red-Black Tree)

红黑树是一种自平衡二叉搜索树(Self-balancing Binary Search Tree) ,由 Rudolf Bayer 于 1972 年发明。它通过在节点上增加一个"颜色"属性(红或黑),并在插入和删除时遵循特定规则,确保树始终保持近似平衡,从而保证查找、插入、删除操作的时间复杂度都是 O(log n)。

一、五条核心性质(必须同时满足)

复制代码
性质1:每个节点要么是红色,要么是黑色
性质2:根节点必须是黑色
性质3:所有叶子节点(NIL/空节点)都是黑色
性质4:红色节点的两个子节点必须是黑色(不能有两个连续的红节点)
性质5:从任一节点到其每个叶子节点的所有简单路径上,黑色节点数量相同(黑高相同)

性质5 是红黑树的灵魂------它保证了最长路径不超过最短路径的 2 倍,从而确保树不会严重倾斜。

二、为什么需要红黑树

普通二叉搜索树的问题

复制代码
        10              10
       /                  \
      5                    15
     /                       \
    3                         20
   /                            \
  1                              25
                                 /
                                22
                                
左图:平衡BST,查找 O(log n)      右图:退化成链表,查找 O(n)

如果按 1, 3, 5, 10, 15, 20, 25 顺序插入,普通 BST 会退化成链表,查找效率变成 O(n)。

红黑树的平衡效果

红黑树通过旋转 + 变色 在插入/删除时自动调整,始终保持近似平衡

复制代码
        [10B]                    [10B]
       /     \                  /     \
     [5R]    [15R]           [5B]     [20B]
    /   \    /    \          /   \    /    \
  [3B] [7B][13B] [20B]    [3R] [7R][15R] [25R]

三、自平衡机制

1. 插入操作

新节点总是以红色 插入(如果插黑色会破坏性质5的黑高平衡)。

插入后可能违反性质4(出现连续红节点),需要修复:

情况 修复方式
叔叔节点是红色 父、叔变黑,祖父变红,向上递归
叔叔是黑色,且新节点是"内侧" 对父节点旋转,转化为外侧情况
叔叔是黑色,且新节点是"外侧" 对祖父节点旋转,父、祖父变色

示例:插入 4 到以下树中

复制代码
    [7B]              [7B]              [7B]              [5B]
   /    \            /    \            /    \            /    \
 [3B]  [10B]  →   [3R]  [10B]  →   [5B]  [10B]  →   [3R]  [7R]
 /                /   \            /   \              /
[1B]            [1B] [4R]       [3B] [4R]          [1B]

2. 删除操作

删除更复杂,核心思路是:

  • 如果删除的是红节点,直接删,不影响黑高
  • 如果删除的是黑节点,会导致该路径黑高减1,需要通过旋转 + 变色 + 兄弟节点借调来恢复平衡

四、时间复杂度

操作 平均 最坏
查找 O(log n) O(log n)
插入 O(log n) O(log n)
删除 O(log n) O(log n)

为什么最坏也是 O(log n)?

由性质5可知:从根到叶子的最短路径全是黑节点,最长路径是红黑交替。

如果树高为 h,最短路径黑节点数 ≥ h/2。

设黑高为 bh,则 n ≥ 2^bh - 1,因此 h ≤ 2log(n+1)。

所以树高最多是 2log(n),查找最多走 2log(n) 步。

五、实际应用场景

红黑树是许多系统核心数据结构的基石:

应用 说明
Java TreeMap / TreeSet 基于红黑树实现的有序映射/集合
Java HashMap(JDK 8+) 链表长度 > 8 时转为红黑树,优化哈希冲突
Linux 内核 完全公平调度器(CFS)使用红黑树管理进程
C++ std::map / std::set 大多数实现(如 GCC)使用红黑树
Epoll / Nginx 管理大量文件描述符的事件
数据库索引 部分内存数据库使用红黑树作为索引结构

六、红黑树 vs AVL 树

对比项 红黑树 AVL 树
平衡度 近似平衡(高度 ≤ 2log n) 严格平衡(高度 ≤ 1.44log n)
查找速度 稍慢(树更高) 更快(树更矮)
插入/删除调整 旋转次数少(O(1) 次旋转) 旋转次数多(O(log n) 次旋转)
适用场景 插入删除频繁 查找频繁、数据静态
实现复杂度 较复杂 更复杂

选型建议

  • 数据变动频繁(如任务调度、实时系统)→ 红黑树
  • 数据基本不变,查询极多(如字典、配置表)→ AVL 树 或哈希表

七、总结

红黑树是一种通过"红节点不能相邻"和"黑高相同"两条规则来约束树高的自平衡二叉搜索树。它牺牲了一定的绝对平衡性,换取了更少的旋转次数,使得插入和删除操作更高效,成为工程实践中应用最广泛的平衡树。

相关推荐
Hi李耶1 小时前
【LeetCode】17.电话号码的字母组合
算法·leetcode·职场和发展
我命由我123451 小时前
Jetpack Compose - @Preview 注解
android·java·java-ee·android studio·android jetpack·android-studio·android runtime
为美好的生活献上中指1 小时前
Spring AI Advisor 深度实战:构建严谨的 AI Agent 拦截链
java·人工智能·spring·advisor·aiagent
2603_965148111 小时前
eBay商品数据API:寻找海外仓与价格洼地
大数据·人工智能·windows·python·microsoft
ruofu331 小时前
如何让docker使用提前下载好的镜像,而不是在线拉取
java·spring cloud·docker
爱敲键盘的猴子1 小时前
深入理解 Spring IoC -- 基于 XML 的 Bean 配置详解
xml·java·spring
艾莉丝努力练剑1 小时前
【Qt:问题解决】Qt程序入口点错误修复:MinGW ABI兼容问题
java·服务器·开发语言·qt·文件系统·动静态库
2601_956319881 小时前
TqSdk Tick 数据适合做什么?获取方法与使用边界
人工智能·python