十三、红黑树

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012736685/article/details/84197476

实际工程中,很多用到平衡二叉查找树的地方都是红黑树。
==》为何是红黑树?而不是其他平衡二叉查找树?

  • 其他二叉树不适用于单次操作时间非常敏感的场景。
  • AVL树对于频繁的插入、删除操作的数据集合代价有些高==》红黑树维护成本比AVL要低

一、平衡二叉查找树

平衡二叉树二叉树中任意一个节点的左右子树的高度相差不能大于1。
完全二叉树、满二叉树都是平衡二叉树;但非完全二叉树也可能是平衡二叉树

在这里插入图片描述

AVL树——最早被发明的平衡二叉查找树

“平衡二叉树”思想:解决普通二叉查找树在频繁的插入、删除等动态更新的情况下,出现时间复杂度退化的问题。
==》整棵树左右更对称些,不要出现左子树很高、右子树很矮的情况,相应的插入、删除、查找等操作的效率高一些。
==》设计新的平衡二叉树,只要树的高度不比log2n大很多,就可以说其实一个合格的平衡二叉树。

1、红黑树(Red-Black Tree,简称R-B Tree)

  • 红黑树是一种不严格的平衡二叉查找树

(1)红黑树

  • 根节点是黑色的;
  • 每个叶子节点都是黑色的空节点(NIL),也就是说,叶子节点不存储数据;
  • 任何相邻节点都不能同时为红色,也就是说,红色节点被黑色节点隔开的;
  • 每个节点,从该节点到其可达叶子节点的所有路径,都包含相同数目的黑色节点。
    在这里插入图片描述

(2)高度分析

  • 将红色节点从红黑树中去掉,只留黑色节点
    ==》有些节点没有父节点,它们会将这些节点的祖父节点作为父节点
    ==》会出现多叉树(eg: 四叉树的情况)
    ==》仅包含黑色节点的多叉树的高度,比包含相同节点个数的完全二叉树的高度要小
    ==》去掉红色节点的“黑树”的高度不超过log2n。
    在这里插入图片描述

  • 将红色节点添加回去——红色节点不能相邻,也就是说有一个红色节点就要至少有一个黑色节点,将其跟其他红色节点隔开
    ==》高度不会超过2log2n,也就是说,红黑树的高度近似2log2n。

(3)小结

红黑树的高度只比高度平衡的AVL树的高度(log2n)仅仅大了一倍,在性能上,下降得并不多。

二、平衡调整

1、左旋(rotate left)和右旋(rotate right)

红黑树的插入、删除操作会破坏红黑树的定义,也就是说,会破坏红黑树的平衡性。

左旋:围绕某个节点的左旋。
右旋:围绕某个节点的右旋。

在这里插入图片描述

2、插入操作的平衡调整

红黑树规定:插入的节点必须是红色的,而且新插入的节点必须放在叶子节点上。

(1)两种特殊情况:

  • 若插入节点的父亲节点是黑色的,则不需要做什么。因为:它仍满足红黑树的定义
  • 若插入的节点是根节点,则直接改变其颜色,将其变为黑色。
  • ==》其他情况,均违背红黑树的定义,则需要进行调整——左右旋转、改变颜色

(2)平衡调整过程——迭代过程

关注关节:正在处理的节点。它会随着不停地迭代处理,而不断发生变化。
==》最开始的关注节点就是新插入的接待呢

新节点插入后,若平衡被打破,则一般会出现下面三种情况:
(这里,将父节点的兄弟节点称为叔叔节点,父节点的父节点称为祖父节点)

case1 : 若关注节点是 a,它的叔叔节点d是红色,则

  • 将关注节点 a 的父节点 b 、叔叔节点 d 的颜色均设置为黑色;
  • 将关注节点 a 的祖父节点 c 的颜色设置为红色;
  • 关注节点变成 a 的祖父节点 c ;
  • 跳转case2 或者 case3
    在这里插入图片描述

case2:若关注节点是a,它叔叔节点d是黑色,关注节点a是其父节点b的右子节点,则:

  • 关注节点变为节点 a 的父节点 b;
  • 围绕新的关注节点 b 左旋;
  • 跳转 case3
    在这里插入图片描述

case3:若关注节点是 a,它叔叔节点 d 是黑色,关注节点 a 是其父节点b的左子结点,则

  • 围绕关注节点 a 的祖父节点 c 右旋;
  • 将关注节点 a 的父节点 b、兄弟节点 c 的颜色互换;
  • 调整结束

3、删除操作的平衡调整

思路:根据关注节点与周围节点的排布特点,按照一定的规则去调整来达到平衡

删除操作的平衡调整方法:

  • 第一步,针对删除节点初步调整。
    • 使其的每个节点,从该节点到达其可达叶子节点的所有路径,都包含相同数目的黑色节点(红黑树定义中最后一条)
  • 第二步,针对关注节点进行二次调整。
    • ==》不存在相邻的两个红色节点(红黑树定义中第三条)

(1)针对删除节点初步调整

注1:有些节点会被标记成两种颜色,“红 - 黑” 或 “黑 - 黑”。若标记为“黑 - 黑”,则在计算黑色节点个数时,要算成两个黑色节点。
注2:画图时:若一个节点既可以是红色,又可以是黑色==》用一半红色一半黑色表示;若一个节点是“红 - 黑”或“黑 - 黑”==》在左上角用小黑点表示额外的黑色。

case1:若要删除的节点是 a,它只有一个子节点 b,则:

  • 删除节点a,并把节点 b 替换到节点 a 的位置;(同普通的二叉树删除操作一样)
  • 节点 a 只能是黑色,节点 b 也只能是红色,其他情况均不符合红黑树定义。这种情况下,将节点 b 改为黑色。。
  • 调整结束,不需要进行二次调整。
    在这里插入图片描述

case2:若要删除的节点 a 有两个非空子节点,并且它的后继节点就是节点 a 的右子节点 c,则

  • 若节点 a 的后继节点就是右子节点 c,那右子节点 c 肯定没有左子树。则把节点 a 删除,并且将节点 c 替换到节点 a 的位置。(该部分与普通的二叉查找树的删除操作相同)
  • 然后将节点 c 的颜色设置为与节点 a 相同的颜色;
  • 若节点 c 是黑色,为了不违反红黑树最后一条定义,将节点 c 的右子节点 d 多加一个黑色,此时节点 d 就成了“红 - 黑”或“黑 - 黑”;
  • 此时,关注节点变成节点 d,第二步的调整就针对关注节点进行操作
    在这里插入图片描述

case3:若要删除的是节点 a,有两个非空子节点,并且节点 a 的后继节点不是右子节点,则:

  • 找到后继节点 d,并将其删除,删除后继节点 d 的过程参考 case 1;
  • 将节点 a 替换成后继结点 d;
  • 把节点 d 的颜色设置为与节点 a 相同的颜色;
  • 若节点 d 是黑色,将节点 d 的右子节点 c 多加一个黑色,则节点 c 变成“红 - 黑”或“黑 - 黑”(红黑树定义最后一条)
  • 关注节点变成节点 c,第二步调整操作针对关注点进行调整。
    在这里插入图片描述

(2)针对关注节点二次调整

经过初步调整,关注节点变成了“红 - 黑”或“黑 - 黑”节点。
二次调整的目的:红黑树中不存在相邻的红色节点
==》四种情况:

case1:若关注节点是 a,其兄弟节点 c 是红色,则:

  • 围绕关注节点 a 的父节点 b 左旋;
  • 关注节点 a 的父节点 b 和 祖父节点 c 交换颜色;
  • 关注节点不变;
  • 继续从四种情况中选择合适的规则来调整。
    在这里插入图片描述

case2:若关注节点是 a,其兄弟节点 c 是黑色,并且节点 c 的 左右子节点 d、e都是黑色,则:

  • 将关注节点 a 的兄弟节点 c 的颜色设置为 红色;
  • 从关注节点 a 中去掉一个黑色==》节点 a 为单纯的红色或黑色;
  • 给关注节点 a 的父节点 b 添加一个黑色==》节点 b 变成“红 - 黑”或者“黑 - 黑”;
  • 关注节点从 a 变成其父节点 b;
  • 继续从四种情况中选择符合的规则来调整。
    在这里插入图片描述

case3:关注节点是 a,其兄弟节点 c 是黑色,c 的左子结点 d 是红色,c 的右子节点 e 是黑色,则:

  • 围绕关注节点 a 的兄弟节点 c 左旋;
  • 节点 c 和节点 d 交换颜色;
  • 关注节点不变;
  • 跳转case4,继续调整。
    在这里插入图片描述

case4:若关注节点 a 的兄弟节点 c 是黑色,且 c 的右子节点是红色,则:

  • 围绕关注节点 a 的父节点 b 左旋;
  • 将关注节点 a 的兄弟节点 c 的颜色,跟关注节点 a 的父节点 b 设置为相同的颜色;
  • 将关注节点 a 的父节点 b 的颜色设置为黑色;
  • 从关注节点 a 中去掉一个黑色,节点 a 就变成单纯的红色或黑色;
  • 将关注节点 a 的叔叔节点 e 设置为黑色;
  • 调整结束。
    在这里插入图片描述

三、TIPs

  • 找准关注节点,不要搞丢、搞错关注节点

猜你喜欢

转载自blog.csdn.net/u012736685/article/details/84197476