数据结构之红黑树

14.红黑树

1.定义:

红黑树是一种自平衡的二叉查找树,是一种高效的查找树。它是由 Rudolf Bayer 于1978年发明,在当时被称为平衡二叉 B 树(symmetric binary B-trees)。后来,在1978年被 Leo J. Guibas 和 Robert Sedgewick 修改为如今的红黑树。红黑树具有良好的效率,它可在 O(logN) 时间内完成查找、增加、删除等操作。

红黑树具备了某些特性的二叉搜索树,能解决非平衡树问题,红黑树是一种接近平衡的二叉树(说它是接近平衡因为它并没有像AVL树的平衡因子的概念,它只是靠着满足红黑节点的5条性质来维持一种接近平衡的结构,进而提升整体的性能,并没有严格的卡定某个平衡因子来维持绝对平衡)

2.特性

在讲解红黑树性质之前,先简单了解一下几个概念:

  • parent:父节点
  • sibling:兄弟节点
  • uncle:叔父节点( parent 的兄弟节点)
  • grand:祖父节点( parent 的父节点)

红黑树同时满足以下特性:

  1. 节点不是黑色,就是红色(非黑即红)
  2. 根节点为黑色
  3. 叶节点为黑色(叶节点是指末梢的空节点 Nil或Null)
  4. 一个节点为红色,则其两个子节点必须是黑色的(根到叶子的所有路径,不可能存在两个连续的红色节点)
  5. 每个节点到叶子节点的所有路径,都包含相同数目的黑色节点(相同的黑色高度)
  • 约束4和5,保证了红黑树的大致平衡:根到叶子的所有路径中,最长路径不会超过最短路径的2倍。
  • 使得红黑树在最坏的情况下,也能有O(log2N)的查找效率
    • 黑色高度为3时,最短路径:黑色→ \rightarrow→ 黑色 → \rightarrow→ 黑色,最长路径:黑色→ \rightarrow→ 红色 → \rightarrow→ 黑色 → \rightarrow→ 红色 → \rightarrow→ 黑色
    • 最短路径的长度为2(不算Nil的叶子节点),最长路径为4
  • 关于叶子节点:Java实现中,null代表空节点,无法看到黑色的空节点,反而能看到传统的红色叶子节点
  • 默认新插入的节点为红色:因为父节点为黑色的概率较大,插入新节点为红色,可以避免颜色冲突

3.红黑树的效率

红黑树的查找,插入和删除操作,时间复杂度都是O(logN)

4.红黑树和AVL树的比较

  • AVL树的时间复杂度虽然优于红黑树,但是对于现在的计算机,cpu太快,可以忽略性能差异
  • 红黑树的插入删除比AVL树更便于控制操作
  • 红黑树整体性能略优于AVL树(红黑树旋转情况少于AVL树)

5.红黑树的等价转换

上面这颗红黑树,我们来将所有的红色节点上移到和他们的父节点同一高度上,就会形成如下结构

这个结构很明显,就是一棵四阶B树(一个节点最多放三个数据),如果画成如下的样子大家应该就能看的更清晰了

由上面的等价变换我们就可以得到如下结论:

  1. 红黑树 和 4阶B树(2-3-4树)具有等价性
  2. 黑色节点与它的红色子节点融合在一起,形成1个B树节点
  3. 红黑树的黑色节点个数 与 4阶B树的节点总个数相等
  4. 在所有的B树节点中,永远是黑色节点是父节点,红色节点是子节点。黑色节点在中间,红色节点在两边。

5.红黑树的左右旋转

可以理解为提着旋转另一侧的孩子节点(左旋提有孩子,右旋提左孩子),将整个树提起来

右旋节点 M 的步骤如下:

  1. 将节点 M 的左孩子引用指向节点 E 的右孩子
  2. 将节点 E 的右孩子引用指向节点 M,完成旋转

以下了解即可

6.插入

默认插入为红色节点

红黑树插入要分情况来看

1.满足红黑树的性质 4

有 4 种情况满足红黑树的性质 4 :parent 为黑色节点。这四种情况不需要做任何额外的处理。

2.不满足性质4,LL RR

RR****情况:父节点为祖父节点的右节点,插入节点为父节点的右节点

LL情况:父节点为祖父节点的左节点,插入节点为父节点的左节点

**判定条件:**uncle 不是红色节点。

  1. parent 染成黑色,grand 染成红色
  2. grand 进行单旋操作
    1. LL:右旋转
    2. RR:左旋转

3.不满足性质4,LR RL

RL****情况:父节点为祖父节点的右节点,插入节点为父节点的左节点

LR情况:父节点为祖父节点的左节点,插入节点为父节点的右节点

**判定条件:**uncle 不是红色节点

  1. 插入节点染成黑色,grand 染成红色
  2. 进行双旋操作
    • LR:parent 左旋转, grand 右旋转
    • RL:parent 右旋转, grand 左旋转

3.上溢的LL插入情况

超出了4阶B树节点的容量范围,这种情况称为上溢

上溢LL情况:父节点为祖父节点的左节点,插入节点为父节点的左节点。并且构成的新的B树节点已经超过了B树节点容量大小范围。

**判定条件:**uncle 是红色节点。满足这个条件的就都是上溢的情况,上溢的修复只需要染色,不需要旋转。

  1. parent、uncle 染成黑色
  2. grand 向上合并
    1. 将向上合并的grand染成红色,相对上一层,就当做是新添加的节点,再次来一遍插入情况的判断,进行处理。

4.上溢的RR插入情况

上溢RR情况:父节点为祖父节点的右节点,插入节点为父节点的右节点。并且构成的新的B树节点已经超过了B树节点容量大小范围。

**判定条件:**uncle 是红色节点

  1. parent、uncle 染成黑色
  2. grand 向上合并
    • 染成红色(其实染成红色就已经是完成了向上合并,因为祖父节点和祖父节点的父节点的连接指向并没有变),当做是新添加的节点进行处理

5.上溢的LR插入情况

上溢LR情况:父节点为祖父节点的左节点,插入节点为父节点的右节点。并且构成的新的B树节点已经超过了B树节点容量大小范围。

**判定条件:**uncle 是红色节点

  1. parent、uncle 染成黑色
  2. grand 向上合并
    • 染成红色,当做是新添加的节点进行处理

6.上溢的RL插入情况

上溢RL情况:父节点为祖父节点的右节点,插入节点为父节点的左节点。并且构成的新的B树节点已经超过了B树节点容量大小范围。

**判定条件:**uncle 是红色节点

  1. parent、uncle 染成黑色
  2. grand 向上合并
    • 染成黑色,当做是新添加的节点进行处理

7.删除

B树中,最后真正被删除的元素都在叶子节点中。所以在红黑树中,被删除的节点一定也在最后一层。

1.删除红色节点

直接删

2.删除拥有1个红色子节点的黑色节点

删除拥有1个红色子节点的黑色节点的情况,是需要我们做相关的处理的。

对于一个二叉树来说,删除一个度为1的节点(度指的是一个节点的子节点个数),将其删除后需要用它唯一的子节点来进行替换。而红黑树的这种情况的判定条件,就是判定要替代删除节点的子节点是不是红色

判定条件:用以替代的子节点是红色节点

修复方法

  1. 用删除节点的唯一子节点对其进行替代
  2. 将替代节点染成黑色

3.删除黑色叶子节点------删除节点为根节点

一棵红黑树只有一个黑色根节点(也就是唯一的一个叶子节点,整个红黑树只有这一个黑色节点),可直接删除该节点,无需做其他操作。

4.删除黑色叶子节点------删除节点的兄弟节点为黑色

因为四阶B树的节点中最少存有1个元素,如果不足,则会造成下溢。也就是需要从兄弟节点中借一个子节点出来。

1.兄弟节点至少有1个红色子节点

黑色叶子节点被删除后,会导致B树节点下溢(比如删除88),就可以从兄弟节点中借出一个红色子节点来进行修复。

**判定条件:**兄弟节点至少有 1 个红色子节点

修复方法:

  1. 进行旋转操作
  2. 旋转之后的中心节点继承父节点(删除节点的父节点)的颜色
  3. 旋转之后的左右节点染为黑色
2.兄弟节点没有红色子节点

当删除节点的兄弟节点没有红色节点可以借出的情况下,就需要父节点来向下合并进行修复,父节点向下和兄弟节点合并成新的B树节点来解决下溢。

**判定条件:**兄弟节点没有1个红色子节点

修复步骤总结:

  1. 父节点向下与兄弟节点进行合并
  2. 将兄弟染成红色、父节点染成黑色即可修复红黑树性质
    • 如果父节点是黑色,直接将父节点当成被删除的节点处理,来修复父节点的下溢情况

5. 删除黑色叶子节点------删除节点的兄弟节点为红色

删除节点的兄弟节点为红色,这样删除节点出现下溢后没办法通过兄弟节点来进行修复。这就需要先把红黑树转换为兄弟节点为黑色的情况,就可以套用上面讲的修复方法来进行修复了。

修复步骤总结:

  1. 兄弟节点染成 BLACK,父节点染成染成 RED,对父节点进行右旋
  2. 于是又回到兄弟节点是黑色的情况(侄子节点变为兄弟节点),继续使用兄弟节点为黑色的方法进行修复
相关推荐
用户37215742613520 分钟前
Java 实现 Excel 与 TXT 文本高效互转
java
浮游本尊1 小时前
Java学习第22天 - 云原生与容器化
java
渣哥3 小时前
原来 Java 里线程安全集合有这么多种
java
间彧3 小时前
Spring Boot集成Spring Security完整指南
java
间彧4 小时前
Spring Secutiy基本原理及工作流程
java
Java水解5 小时前
JAVA经典面试题附答案(持续更新版)
java·后端·面试
洛小豆7 小时前
在Java中,Integer.parseInt和Integer.valueOf有什么区别
java·后端·面试
前端小张同学7 小时前
服务器上如何搭建jenkins 服务CI/CD😎😎
java·后端
ytadpole7 小时前
Spring Cloud Gateway:一次不规范 URL 引发的路由转发404问题排查
java·后端
华仔啊7 小时前
基于 RuoYi-Vue 轻松实现单用户登录功能,亲测有效
java·vue.js·后端