算法 — 二叉树之红黑树(三)

背景:红黑树其实就是一种数据结构,设计它的目的就是为了高效地进行增删改查。普通的二叉查找树在极端情况下可退化成链表,此时的增删查O(n)效率都会比较低下。为了避免这种情况,就出现了红黑树。而红黑树是基于二叉查找树和平衡二叉树的基础上增加了自动维持平衡的性质,插入、搜索、删除的效率都比较高。红黑树之所以难是难在它是自平衡的二叉查找树,在进行插入和删除等可能会破坏树的平衡的操作时,需要重新自处理达到平衡状态。我们先回顾下二叉查找树和平衡二叉树

二叉查找树

1. 特征

  • 节点的左子树小于节点本身
  • 节点的右子树大于节点本身
  • 左右子树同样为二叉搜索树

下图就是一棵典型的二叉搜索树:
在这里插入图片描述
2. 查找过程
第一步:首先查找到根节点,值为 60 的节点。
在这里插入图片描述

第二步:比较我们要找的值 58 与该节点的大小。
如果等于,那么恭喜,已经找到;如果小于,继续找左子树;如果大于,那么找右子树。
很明显 58<60,因此我们找到左子树的节点 56,此时我们已经定位到了节点 56。
在这里插入图片描述

第三步:按照第二步的规则继续找。
58>56 我们需要继续找右子树,定位到了右子树节点 58,恭喜,此时我们已经找到了。
在这里插入图片描述

我们经过三步就已经找到了,其实就是我们平时所说的二分查找,这种二叉搜索树好像查找效率很高,但同样它也有缺陷,如下面这样的二叉搜索树。
在这里插入图片描述

看到这样的二叉搜索树是否很别扭,典型的大长腿瘸子,但它也是二叉搜索树,如果我们要找值为 50 的节点,基本上和单链表查询没多大区别了,性能将大打折扣。
这个时候我们的均衡二叉树就粉墨登场了,均衡二叉树就是在二叉搜索树的基础上添加了自动维持平衡的性质。

平衡二叉树

上面的大长腿瘸子二叉搜索树经过自动平衡后,可能就成为了下面这样的二叉树。经过了自动平衡,再去找值为 50 的节点,查找性能将提升很多。红黑树就是非严格均衡的二叉搜索树。
在这里插入图片描述

上面这颗二叉树就是平衡二叉树,也叫作AVL树。仔细分析你会发现如下特点:
(1)从任何一个节点出发,左右子树深度之差的绝对值不超过1。
(2)左右子树仍然为平衡二叉树。

我们发现经过调整之后,我们二叉树就重新回到了平衡。从上面这个过程我们会发现,平衡二叉树真的很不错,在查找时既有着二叉查找树的优越性,在插入时还能通过调整继续保持着。那么为什么还要使用到红黑树呢?我觉得可以从以下两个方面来考虑:
(1)删除:对于平衡二叉树来说,在最坏情况下,需要维护从被删节点到根节点这条路径上所有节点的平衡性,旋转的量级是O(logN)。但是红黑树就不一样了,最多只需3次旋转就会重新平衡,旋转的量级是O(1)。
(2)保持平衡:平衡二叉树高度平衡,这也就意味着在大量插入和删除节点的场景下,平衡二叉树为了保持平衡需要调整的频率会更高。

注意:在大量查找的情况下,平衡二叉树的效率更高,也是首要选择。在大量增删的情况下,红黑树是首选。

红黑树

红黑树是一种特殊的二叉查找树,每个结点都要储存位表示结点的颜色,或红或黑

特征
  1. 节点是红色或黑色。
  2. 根是黑色。
  3. 所有叶子都是黑色(叶子是NIL节点)。
  4. 每个红色节点必须有两个黑色的子节点。(从每个叶子到根的所有路径上不能有两个连续的红色节点。)
  5. 从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点(简称黑高)。

有了上面的几个性质作为限制,即可避免二叉查找树退化成单链表的情况。但是,仅仅避免这种情况还不够,这里还要考虑某个节点到其每个叶子节点路径长度的问题。如果某些路径长度过长,那么,在对这些路径上的及诶单进行增删查操作时,效率也会大大降低。这个时候性质4和性质5用途就凸显了,有了这两个性质作为约束,即可保证任意节点到其每个叶子节点路径最长不会超过最短路径的2倍。

当某条路径最短时,这条路径必然都是由黑色节点构成。当某条路径长度最长时,这条路径必然是由红色和黑色节点相间构成(性质4限定了不能出现两个连续的红色节点)。而性质5又限定了从任一节点到其每个叶子节点的所有路径必须包含相同数量的黑色节点。此时,在路径最长的情况下,路径上红色节点数量 = 黑色节点数量。该路径长度为两倍黑色节点数量,也就是最短路径长度的2倍。

示意图:(红黑树首先是一颗搜索树,所以左子树点小于根结点,右子树大于根节点,等于根结点的按照自己的需要放左边和右边都是可以的)(红黑树不仅是一颗搜索树还是一颗非严格的平衡树)
在这里插入图片描述

2.自旋操作

红黑树的基本操作是添加和删除,在对红黑树进行添加和删除之后,都会用到旋转方法,为什么呢?道理很简单,因为添加或者删除红黑树中的结点之后,红黑树就发生了变化,可能不满足上面的5条性质了,这个时候就需要通过旋转操作来保证它依旧是一棵红黑树,旋转分为左旋和右旋;(旋转操作仅仅只是用来调节结点的位置的,就是为了满足红黑树的性质5)

2.1 左旋
如下图所示,左旋是将X的右子树绕X逆时针旋转,使得X的右子树成为X的父亲,同时修改相关结点的引用,旋转之后,要求二叉查找树的属性依然满足
在这里插入图片描述
2.2 右旋
右旋是将X的左子树绕X顺时针旋转,使得X的左子树成为X的父亲,同时注意修改相关结点的引用,旋转之后要求仍然满足搜索树的属性
在这里插入图片描述

3.添加操作

添加操作过程:首先将红黑树当作一颗查找树一样将结点插入,然后将结点着为红色,最后通过旋转和重新着色的方法使之重新成为红黑树;

将新加入的结点涂成红色的原因:
1)不违背红黑树的性质5:从任意一个结点出发到空叶子结点,经过的黑色结点个数相同
2)按照红黑树的性质4我们知道红黑树中黑结点的个数至少是红结点个数的两倍,所以新增结点的父亲结点是黑结点的概率比较大,如果新增结点的父节点为黑色,那么此时不需要再去进行任何调整操作,因此效率很高,所以新结点应该涂成红色;

现在我们来分析一下新增的结点(红色)插入之后可能面临的几种情况,以及他们的处理措施:

  1. 插入的结点为根结点
    将新插入的红色结点变成黑色结点,满足根结点为黑色结点的要求!

  2. 父亲结点为黑色结点
    这个时候不需要进行任何调整操作,此时的树仍然是一颗标准的红黑树

  3. 父亲结点为红色结点的情况下,叔叔结点为红色结点(不用考虑左右)
    解决方案:将叔叔和父亲结点改为黑色,爷爷结点改为红色,未完
    然后又将爷爷结点当作插入结点看待,一直进行上面的操作,直到当前结点为根结点,然后将根结点变成黑色
    原图:
    在这里插入图片描述
    插入一个125的结点:
    在这里插入图片描述
    现在125结点和130结点都是红色的,显然违背了规则4,所以将新插入结点的父亲130结点和插入结点的叔叔结点150变成黑色,并将新插入结点的爷爷结点140变成红色,图如下:
    在这里插入图片描述
    然后又将140结点当作新插入结点处理(因为140结点和新插入结点面临的情况都是一样的:和父亲结点都是红色),也就是做如下处理:将140结点的父亲结点120和140的叔叔结点60变成黑色结点,将140结点的爷爷结点变成红色,因为遍历到了根结点,要满足根结点是黑色的性质要求,所以又将140的爷爷结点也就是根结点变成黑色,图如下:
    在这里插入图片描述
    到这里,为新插入结点125所做的某些结点重新着色的操作就完成了,现在该树是标准的红黑树了!

  4. 新插入的结点的父亲结点为红色,其叔叔结点为黑色,
    1)父亲结点为爷爷结点的左孩子,新插入结点为父节点的左孩子(左左情况)
    2)父亲结点为爷爷结点的右孩子,新插入结点为父亲结点的右孩子(右右情况)
    比如下图,新插入结点为25,其父亲结点30为红色,其叔叔结点为空黑色叶子结点,且新插入结点和其父节点都是左孩子:
    在这里插入图片描述
    我们将其父亲结点和爷爷结点颜色互换,然后针对爷爷结点进行一次左旋,图如下:
    在这里插入图片描述

  5. 新插入的结点的父亲结点是红色,其叔叔结点是黑色
    1)插入结点是右结点,父节点是左结点
    2)插入结点是左结点,父亲结点是右结点
    上述两种情况都是同一个处理办法
    比如下图,新插入结点是126,其父结点125为红色,其叔叔结点为空的黑色结点,而且插入结点是右结点,父结点是左结点:
    在这里插入图片描述
    我们将父亲结点125看作当前结点进行左旋,旋转结果如下:
    在这里插入图片描述
    现在我们的当前结点是125,现在125的处境和上面的情况4是一样的(父节点为红,叔叔结点为黑,插入结点为左结点,父亲结点也为左孩子)现在我们继续按照情况4的处理办法处理上述情况(措施和情况4一样,父亲结点和爷爷结点互换颜色,然后针对爷爷结点进行左旋),处理后情况如下:
    在这里插入图片描述

4、删除操作

删除结点的过程原理:首先将红黑树当作一个二叉查找树,将该结点从二叉查找树中删除,然后通过一些列重新着色操作等一系列措施来修正该树,使之重新成为一颗红黑树。
删除操作首先要确定待删除节点有几个孩子,如果有两个孩子,不能直接删除该节点。而是要先找到该节点的前驱(该节点左子树中最大的节点)或者后继(该节点右子树中最小的节点),然后将前驱或者后继的值复制到要删除的节点中,最后再将前驱或后继删除。由于前驱和后继至多只有一个孩子节点,这样我们就把原来要删除的节点有两个孩子的问题转化为只有一个孩子节点的问题,问题被简化了一些。

删除一个节点有以下四种情况:

  1. 删除的节点没有孩子
  2. 删除的节点只有左子树
  3. 删除的节点只有右子树
  4. 删除的节点拥有左子树和右子树

其实只有上面前三种情况,对于第四种情况,可以找到待删除节点的直接后继节点,用这个节点的值替代待删除节点,接着情况转变为删除这个直接后继节点,情况也变为前三种之一。

1.删除的节点只有左子树或只有右子树

在这里插入图片描述在这里插入图片描述
只有上面两种情况会存在于红黑树中,直接用DL/DR的元素值代替D的元素,再把DL/DR直接删去就好。

2.删除的节点没有孩子
1)待删除节点是红色的,直接删去这个节点。
2)父节点P是红色节点
解决方案:把P节点染成黑色,兄弟节点染成红色,删除节点D。
在这里插入图片描述
3)兄弟节点S是红色节点
解决方案:把P染成红色,S染成黑色,然后以P为轴做相应的旋转操作(D为P的左子树则左旋,否则右旋),变成了情况2(父节点为红色),按照情况2进行操作。
在这里插入图片描述
4)节点D的远亲侄子为红色节点的情况(父节点P可红可黑)
解决方案:交换P和S的颜色,然后把远亲侄子节点SR/SL设置为黑色,再已P为轴做相应的旋转操作(D为P的左子树则左旋,否则右旋),删除节点D。
在这里插入图片描述
5)节点D的近亲侄子为红色节点的情况(父节点P可红可黑)
解决方案:把S染成红色,把近亲侄子节点SR/SL染成黑色,然后以节点S为轴做相应的旋转操作(D为P的左子树则右旋,否则左旋),变成了情况4,按照情况4进行操作。
在这里插入图片描述
6)节点D,P,S均为黑色节点
在这里插入图片描述
解决方案:把D删去,然后把节点S染成红色。
①从节点P往上依然是全黑的情况
在这里插入图片描述
②从节点P往上是其他情况
在这里插入图片描述

引用:https://www.cnblogs.com/panda28/p/11132462.html
     https://www.cnblogs.com/yinbiao/p/10732600.html
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

RachelHwang

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

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

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

打赏作者

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

抵扣说明:

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

余额充值