【Java数据结构与算法】第十四章 红黑树

第十四章 红黑树

一、红黑树

1.介绍

红黑树(Red Black Tree)是平衡二叉树的其中一种实现方式,解决了二叉排序树多次插入新结点导致的不平衡问题

在这里插入图片描述

除了二叉排序树的基本特性外,它还具有下列附加规则:

  1. 结点是红色或黑色
  2. 根结点是黑色
  3. 每个叶子结点都是黑色的空结点(NIL 结点)
  4. 每个红色结点的两个子结点都是黑色(从每个叶子到根的所有路径上不能有两个连续的红色结点)
  5. 从任一结点到其每个叶子的所有路径都包含相同数目的黑色结点
  6. 平衡二叉树是严格平衡的二叉树,要求每个结点的左右子树高度差不超过 1。而红黑树则要宽松一些,只要求任何一条路径的长度不超过其他路径长度的 2 倍

当插入或删除结点的时候,红黑树的规则可能被打破。这时候就需要做出一些调整,从而继续维持我们的规则

向原红黑树插入值为 14 的新结点
在这里插入图片描述

由于父结点 15 是黑色结点,因此这种情况并不会破坏红黑树的规则,无需做任何调整

向原红黑树插入值为 21 的新结点
在这里插入图片描述

由于父结点 22 是红色结点,因此这种情况打破了红黑树的规则 4(每个红色结点的两个子结点都是黑色),必须进行调整,使之重新符合红黑树的规则

调整的方法有变色和旋转,和常规的平衡二叉树一样,旋转包含左旋转和右旋转

变色:

为了重新符合红黑树的规则,尝试把红色结点变为黑色,或者把黑色结点变为红色

下图所表示的是红黑树的一部分(子树),新插入的结点 Y 是红色结点,它的父结点 X 也是红色的,不符合规则 4,因此我们可以把结点 X 从红色变为黑色

在这里插入图片描述

但是,仅仅把一个结点变色,会导致相关路径凭空多出一个黑色结点,这样就打破了规则 5。因此,我们需要对其它结点做进一步的调整,后文会详细说明

2.插入结点

红黑树插入新结点的时候可以分为 5 种不同的局面,每一种局面有不同的调整方案

局面 1:新结点(A)位于树根,没有父结点

在这里插入图片描述

空心三角形代表结点下面的子树

这种局面,直接让新结点变色为黑色,规则 2 得到满足。同时,黑色的根结点使得每条路径上的黑色结点数目都增加了 1,所以并没有打破规则 5

在这里插入图片描述

局面 2:新结点(B)的父结点是黑色

这种局面,新插入的红色结点 B 并没有打破红黑树的规则,所以不需要做任何调整

在这里插入图片描述

局面 3:新结点(D)的父结点和叔叔结点都是红色
在这里插入图片描述

这种局面,两个红色结点 B 和 D 连续,违反了规则 4,因此我们先让结点 B 变为黑色

在这里插入图片描述

这样一来,结点 B 所在路径凭空多了一个黑色结点,打破了规则 5,因此我们让结点 A 变为红色:

在这里插入图片描述

这时候,结点 A 和 C 又成为了连续的红色结点,我们再让结点 C 变为黑色

在这里插入图片描述

经过上面的调整,这一局部重新符合了红黑树的规则

局面 4:新结点(D)的父结点是红色,叔叔结点是黑色或者没有叔叔,且新结点是父结点的右子结点,父结点(B)是祖父结点的左子结点

在这里插入图片描述

我们以结点 B 为轴,做一次左旋转,使得新结点 D 成为父结点,原来的父结点 B 称为 D 的左子结点

在这里插入图片描述

这样一来,进入了局面 5

局面 5:新结点(D)的父结点是红色, 叔叔结点是黑色或者没有叔叔,且新结点是父结点的左子结点,父结点(B)是祖父结点的左子结点

在这里插入图片描述

我们以结点 A 为轴,做一次右旋转,使得结点 B 成为祖父结点,结点 A 成为结点 B 的右子结点:

在这里插入图片描述

接下来,我们让结点 B 变为黑色,结点 A 变为红色

在这里插入图片描述

经过上面的调整,这一局部重新符合了红黑树的规则

如果局面 4 中的父结点(B)是右子结点,则成为了局面 5 的镜像,原本的右旋转改为左旋转

如果局面 5 中的父结点(B)是右子结点,则成为了局面 4 的镜像,原本的左旋转改为右旋转

我们不用刻意记住这些局面的处理方式,只需要有个大概了解即可

实例演示:

给定下面这棵红黑树,新插入的结点是 21

在这里插入图片描述

显然,新结点 21 和它的父结点 22 是连续的红色结点,违背了规则 4,我们应该如何调整呢?

让我们回顾一下刚才讲的 5 种局面,当前的情况符合局面 3:新结点的父结点和叔叔结点都是红色

于是我们经过三次变色,22 变为黑色,25 变为红色,27 变为黑色

在这里插入图片描述

经过上面的调整,以结点 25 为根的子树符合了红黑树规则,但结点 25 和结点 17 成为了连续的红色结点,违背了规则 4

于是,我们把结点 25 看作一个新结点,正好符合局面 5 的镜像:新结点的父结点是红色,叔叔结点是黑色或者没有叔叔,且新结点是父结点的右子结点,父结点是祖父结点的右子结点

于是我们以根结点 14 为轴进行左旋转,使得结点 17 成为了新的根结点

在这里插入图片描述

接下来,让结点 17 变为黑色,结点 13 变为红色

在这里插入图片描述

如此一来,我们的红黑树变得重新符合规则

3.删除结点

第一步:如果待删除结点有两个非空的子结点,转化成待删除结点只有一个子结点(或者没有子结点)的情况

在这里插入图片描述

上面的例子是一棵红黑树的局部,标数字的三角形代表任意形态的子树,假设结点 8 是待删除结点

根据上文讲解的二叉查找树的删除流程,由于结点 8 有两个子结点,我们选择仅大于 8 的结点 10 复制到 8 的位置,结点颜色变成待删除结点的颜色

在这里插入图片描述

接下来我们需要删除红色的结点 10

在这里插入图片描述

红色结点 10 能成为仅大于 8 的结点,必定没有左子结点,所以问题转换成了待删除结点只有一个右子结点(或没有子结点)的情况,接下来我们进入第二步

第二步:根据待删除结点和其唯一子结点的颜色,分情况处理

情况 1,自身是红色,子结点是黑色

在这里插入图片描述

这种情况最简单,按照二叉排序树的删除操作,删除结点 1 即可

在这里插入图片描述

情况 2,自身是黑色,子结点是红色:
在这里插入图片描述

这种情况也很简单,首先按照二叉查找树的删除操作,删除结点 1

在这里插入图片描述

此时,这条路径凭空减少了一个黑色结点,那么我们需要再把结点 2 变成黑色

在这里插入图片描述

情况 3,自身是黑色,子结点也是黑色,或者子结点是空叶子结点

在这里插入图片描述

这种情况最复杂,涉及到很多变化。首先我们还是按照二叉排序树的删除操作,删除结点 1

在这里插入图片描述

显然,这条路径上减少了一个黑色结点,而且结点 2 再怎么变色也解决不了

这时候我们进入第三步,专门解决父子双黑的情况

第三步:遇到双黑结点,在子结点顶替父结点之后,分成 6 种情况处理

情况 1,结点 2 是红黑树的根结点:

在这里插入图片描述

此时所有路径都减少了一个黑色结点,并未打破规则,不需要调整

情况 2,结点 2 的父亲、兄弟、侄子结点都是黑色

在这里插入图片描述

此时,我们直接把结点 2 的兄弟结点 B 改为红色

在这里插入图片描述

这样一来,原本结点 2 所在的路径少了一个黑色结点,现在结点 B 所在的路径也少了一个黑色结点,两边“扯平”了

可是,结点 A 以下的每一条路径都减少了一个黑色结点,与结点 A 之外的其它路径又造成了新的不平衡呢?

没关系,我们让结点 A 扮演原先结点 2 的角色,进行递归操作,重新判断各种情况

情况 3,结点2的兄弟结点是红色

在这里插入图片描述

首先以结点 2 的父结点 A 为轴,进行左旋转

在这里插入图片描述

然后将结点 A 变成红色、结点 B 变成黑色

在这里插入图片描述

这样的意义是什么呢?结点 2 所在的路径仍然少一个黑色结点呀?

别急,这样的变化有可能转换成情况 4、5、6 中的任意一种,在情况 4、5、6 当中会进一步解决

情况 4,结点 2 的父结点是红色,兄弟和侄子结点是黑色

在这里插入图片描述

这种情况,我们直接让结点 2 的父结点 A 变成黑色,兄弟结点 B 变成红色

在这里插入图片描述

这样一来,结点 2 的路径补充了黑色结点,而结点 B 的路径并没有减少黑色结点,重新符合了红黑树的规则

情况 5,结点 2 的父结点随意,兄弟结点 B 是黑色右子结点,左侄子结点是红色,右侄子结点是黑色

在这里插入图片描述

这种情况下,首先以结点 2 的兄弟结点 B 为轴进行右旋转

在这里插入图片描述

接下来结点 B 变为红色,结点 C 变为黑色

在这里插入图片描述

这样的变化转换成了情况 6

情况 6,结点 2 的父结点随意,兄弟结点 B 是黑色右子结点,右侄子结点是红色

在这里插入图片描述

首先以结点 2 的父结点 A 为轴左旋转

在这里插入图片描述

接下来让结点 A 和结点 B 的颜色交换,并且结点 D 变为黑色

在这里插入图片描述

经过结点 2 的路径由(随意+黑)变成了(随意+黑+黑),补充了一个黑色结点

经过结点 D 的路径由(随意+黑+红)变成了(随意+黑),黑色结点并没有减少

所以,这时候重新符合了红黑树的规则

实例演示:

给定下面这棵红黑树,待删除的是结点 17

在这里插入图片描述

第一步,由于结点 17 有两个子结点,子树当中仅大于 17 的结点是 25,所以把结点 25 复制到 17 位置,保持黑色

在这里插入图片描述

接下来,我们需要删除原本的结点 25

在这里插入图片描述

这个情况正好对应于第二步的情况三,即待删除结点是黑色,子结点是空叶子结点

于是我们删除框框中结点 25,进入第三步

在这里插入图片描述

此时,框框中的结点虽然是空叶子结点,但仍然可以用于判断局面,当前局面符合情况 5 的镜像

在这里插入图片描述

在这里插入图片描述

于是我们通过左旋和变色,把子树转换成情况 6 的镜像

在这里插入图片描述

再经过右旋和变色,子树最终成为了下面的样子

在这里插入图片描述

在这里插入图片描述

这样一来,整棵二叉树又重新符合了红黑树的规则

4.与平衡二叉树的对比

平衡二叉树是严格平衡的二叉树,要求每个结点的左右子树高度差不超过 1。而红黑树则要宽松一些,只要求任何一条路径的长度不超过其他路径长度的 2 倍

正因为这个差别,二叉平衡树的查找效率更高,但平衡调整的成本也更高,在需要频繁查找时,选用二叉平衡树更合适,在需要频繁插入删除时,选用红黑树更合适

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

313YPHU3

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值