【树】 红黑树(通俗易懂)

本文首先介绍了二叉查找树的基本概念及其在查找、插入、删除操作上的性能优势,随后深入探讨了红黑树作为一种平衡二叉查找树的实现方式,通过其独特的性质确保了树的高度始终保持在logn,从而保证了复杂度为O(logn)的操作效率。

教你透彻了解红黑树

二叉查找树

由于红黑树本质上就是一棵二叉查找树,所以在了解红黑树之前,咱们先来看下二叉查找树。

二叉查找树(Binary Search Tree),也称有序二叉树(ordered binary tree),排序二叉树(sorted binary tree),是指一棵空树或者具有下列性质的二叉树:

  • 若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
  • 若任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
  • 任意节点的左、右子树也分别为二叉查找树。
  • 没有键值相等的节点(no duplicate nodes)。

因为,一棵由n个结点,随机构造的二叉查找树的高度为lgn,所以顺理成章,一般操作的执行时间为O(lgn).(至于n个结点的二叉树高度为lgn的证明,可参考算法导论 第12章 二叉查找树 第12.4节)。

但二叉树若退化成了一棵具有n个结点的线性链后,则此些操作最坏情况运行时间为O(n)。后面我们会看到一种基于二叉查找树-红黑树,它通过一些性质使得树相对平衡,使得最终查找、插入、删除的时间复杂度最坏情况下依然为O(lgn)


红黑树

前面我们已经说过,红黑树,本质上来说就是一棵二叉查找树,但它在二叉查找树的基础上增加了着色和相关的性质使得红黑树相对平衡,从而保证了红黑树的查找、插入、删除的时间复杂度最坏为O(log n)。

但它是如何保证一棵n个结点的红黑树的高度始终保持在h = logn的呢?这就引出了红黑树的5条性质:

1)每个结点要么是红的,要么是黑的。  
2)根结点是黑的。  
3)每个叶结点(叶结点即指树尾端NIL指针或NULL结点)是黑的。  
4)如果一个结点是红的,那么它的俩个儿子都是黑的。  
5)对于任一结点而言,其到叶结点树尾端NIL指针的每一条路径都包含相同数目的黑结点。  

正是红黑树的这5条性质,使得一棵n个结点是红黑树始终保持了logn的高度,从而也就解释了上面我们所说的“红黑树的查找、插入、删除的时间复杂度最坏为O(log n)”这一结论的原因。

如下图所示,即是一颗红黑树(下图引自wikipedia:http://t.cn/hgvH1l):





关于插入和删除,未完待续

<think> 我们之前已经详细解释了红黑树的用途,现在用户希望以通俗易懂的方式,结合实际案例红黑树原理并给出Java实现演示。根据引用内容,特别是引用[1]和引用[2],我们可以这样安排: 1. **通俗原理解**:用现实案例(如字典查找)解释红黑树的五大规则和自平衡原理。 2. **核心操作演示**:插入和删除的修复逻辑(旋转与变色),结合具体步骤。 3. **Java实现演示**:基于引用[2]中的TreeMap示例,展示红黑树在实际代码中的应用。 4. **性能对比**:简要说明红黑树与普通二叉搜索的效率差异。 注意:引用[1]强调要覆盖核心规则和修复逻辑,引用[2]提供了TreeMap的使用示例,我们将结合这两点。 下面开始组织回答: </think> ### 红黑树原理与Java实现:通俗解析 #### 一、红黑树的核心原理(以图书馆管理系统为例) 想象图书馆的书架需要**动态整理书籍**: 1. **书架规则(红黑树5大约束)** - 每本书有红/黑标签(节点颜色) - 书架入口(根节点)必须黑色 - 相邻书不能全红(红色节点子节点必须黑) - 每条路径的黑色书数量相同(黑高一致) - 空位置视为黑色叶子节点(NIL节点) 2. **自平衡机制** 当新增/移除书籍破坏规则时,触发两种操作: - **变色**:调整书标签颜色(最低成本修复) - **旋转**:局部调整书架结构(分左旋/右旋) ```mermaid graph LR A[插入节点] --> B{是否破坏规则?} B -->|否| C[维持现状] B -->|是| D[执行变色或旋转] D --> E[向上递归检查] ``` #### 二、Java实现演示(基于TreeMap) ```java import java.util.TreeMap; public class LibrarySystem { public static void main(String[] args) { // 创建红黑树结构的图书索引(TreeMap底层为红黑树[^2]) TreeMap<Integer, String> bookIndex = new TreeMap<>(); // 1. 插入书籍(自动平衡) bookIndex.put(101, "算法导论"); // 根节点黑 bookIndex.put(205, "Java编程"); // 红色节点 bookIndex.put(88, "数据结构"); // 触发左旋转 // 2. 范围查询(中序遍历有序性) System.out.println("80-100编号的书籍: " + bookIndex.subMap(80, 100)); // 输出: {88=数据结构} // 3. 删除书籍(自动修复平衡) bookIndex.remove(205); System.out.println("删除后的索引: " + bookIndex); // 输出: {88=数据结构, 101=算法导论} } } ``` #### 三、关键操作原理详解 1. **插入修复(双红冲突)** - 场景:新书(红)插入到红书旁边 - 解决方案: ```java if (叔节点为红) { 父、叔变黑,祖父变红; // 变色解决 } else { 旋转(左旋/右旋) + 变色; // 示例:插入88触发左旋[^1] } ``` 2. **删除修复(黑高失衡)** - 场景:删除黑书导致路径黑书减少 - 解决方案: ```java while (当前节点黑且非根) { if (兄弟节点为红) { 兄弟变黑,父变红,旋转父节点; } if (兄弟子节点全黑) { 兄弟变红,当前=父节点; // 向上递归 } else { 旋转 + 变色调整; // 重建黑高平衡 } } ``` #### 四、红黑树 vs 普通二叉搜索 | 操作 | 普通BST | 红黑树 | 优势说明 | |------------|----------------|----------------------|---------------------------| | 插入 | 可能退化成链表 | 自动平衡($O(\log n)$) | 避免极端低效 | | 删除 | 破坏结构 | 动态修复黑高 | 保证后续操作稳定 | | 范围查询 | 需全遍历 | 中序遍历即有序($O(k)$) | 适合图书馆按编号查书场景 | > **核心价值**:红黑树通过**非严格平衡**(允许黑高差1)减少旋转次数,比AVL更适合频繁修改的场景[^1]。在Java的`TreeMap`中,这种结构使得插入/删除/查询都能稳定在$O(\log n)$时间完成[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值