红黑树(下):掌握这些技巧,你也可以实现一个红黑树

红黑树(下):掌握这些技巧,你也可以实现一个红黑树

实现红黑树的基本思想

一棵合格的红黑树需要满足四个要求,但是在插入、删除的过程中,第三点、第四点可能会被破坏,所以需要平衡调整

左旋(rotate left)围绕某个节点的左旋和右旋(rotate right)围绕某个节点右旋

插入操作的平衡调整

插入的结点必须是红色的,而且二叉查找树中新插入的节点都是放在叶子节点上的,所以关于插入操作的平衡调整,有两种特殊情况

1.如果插入结点的父节点是黑色的,什么都不用做

2.如果插入的结点是根节点,直接改变它的颜色,变成黑色即可

除此之外,就需要调整:左右旋转和改变颜色

红黑色的平衡调整过程是一个迭代的过程,把正在处理的节点叫做关注节点,关注节点会随着不停地迭代处理不断发生变化,最开始的关注节点就是新插入的节点

新节点插入后,如果平衡被打破,有三种情况:ps:父节点的兄弟节点叫做叔叔节点,父节点的父节点叫做祖父节点

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的颜色互换
  • 调整结束

删除操作的平衡调整

只需要根据关注节点与周围节点的排布特点,按照一定的规则调整即可

删除操作的平衡调整有两步:一是针对删除结点初步调整二是针对关注节点进行二次调整

1.针对删除结点初步调整

在初步调整之后,有些节点会被标记成两种颜色,“红-黑”或者“黑-黑”,如果是“黑-黑”,计算黑色节点个数的时候,会算成两个黑色节点

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的过程参照CASE1
  • 将节点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的颜色跟其父节点b设置成相同的颜色
  • 将a的父节点b的颜色设置为黑色
  • 从a中去掉一个黑色,a就变成了红色或黑色
  • 将a的叔叔节点e设置为黑色
  • 调整结束

代码实现:

https://www.cnblogs.com/alantu2018/p/8462017.html

发布了76 篇原创文章 · 获赞 9 · 访问量 9195

猜你喜欢

转载自blog.csdn.net/ywangjiyl/article/details/104362668
今日推荐