红黑树(平衡操作详解)

1.红黑树     红黑树本身也是一种二叉树,只不过是一种比较特殊的二叉树

    二叉树如果插入的数值是有序时,二叉树就是非平衡的,基本跟链表类似了(时间复杂度O(N))

    针对这种情况,就产生了红黑树,这种树在插入的过程中,会通过一系列的方式来保持树的平衡,使其时间复杂度一直维持在O(logN)

2.红黑树规则

    * 每一个节点不是黑色就是红色     * 根节点总是黑色的

    * 如果节点是红色的,则它的子节点必须是黑色的(反之则不一定)

    * 从根到叶节点的每条路径,包含的黑色节点数目必须相同

3.红黑树修正违规操作简介

    红黑树之所以能够保持平衡,是因为严格遵守了上述规则

    在插入的过程中,如果某节点违反了以上规则,则需要进行修正,修正的方式包括:改变颜色、旋转

    1)术语

        为了平衡一棵树,需要对某些节点进行重新排列,将一些节点上升,将一些节点下降,以此来帮助树平衡。

        切记:在树平衡操作的过程中不能破坏二叉树的特点(
一个节点的左子节点的关键字值小于这个节点,右子节点的关键字值大于或等于这个父节点

        旋转之前先了解一些基本概念:

       
 
* 外侧子孙
《红黑树(平衡操作详解)》
12在18的左侧,18在25的左侧,它们的相对父节点位置相同,则称新插入的节点12为外侧子孙节点
《红黑树(平衡操作详解)》 38在35的右侧,35在25的右侧,
它们的相对父节点位置相同,则称新插入的节点38为外侧子孙节点

        

       
 * 内侧子孙
《红黑树(平衡操作详解)》       
22在18的右侧,18在25的左侧,它们的相对父节点位置不同,则称新插入的节点22为内侧子孙节点
《红黑树(平衡操作详解)》
30在35的左侧,35在25的右侧,
它们的相对父节点位置不同,则称新插入的节点30为内侧子孙节点

        可以看到,在插入新节点之前的树都是平衡的,但是插入新节点之后就会违反规则3,故需要对这些树进行修正(看到子节点和父节点都是红色的,就要想到使用旋转来保持树的平衡)

        * 右旋转

《红黑树(平衡操作详解)》

当以35为顶端元素进行右旋转时,需要注意:该顶端元素必须有一个左子元素

右旋结果如下:

《红黑树(平衡操作详解)》 35下移,30上移到35的位置,20位置不变,依旧是30的左子元素

        * 左旋转

《红黑树(平衡操作详解)》

当以30为顶端元素进行左旋转时,需要注意:该顶端元素必须有一个右子节点 左旋结果如下:

《红黑树(平衡操作详解)》 30下移到左侧,35上移到30的位置,45位置不变,依旧是35的右子节点

    2)颜色变换

        场景:当在插入的过程中遇到一个黑色节点下有两个红色节点,则需要进行颜色变换

        示例:

《红黑树(平衡操作详解)》         当前场景下,是符合红黑树规则的,如果此时再插入一个节点,按照规则3,则新节点只能是黑色的,但是这样就会违反规则4,所以对现有节点进行变色         * 把25、75两个子节点变色为黑色         * 再新插入节点为红色即可

操作完成之后的树为

《红黑树(平衡操作详解)》
  
 


    3)外侧子孙的旋转平衡术
《红黑树(平衡操作详解)》
针对上述这种情况,找到新插入节点12的祖父节点25,然后以25为顶端,进行右旋转


《红黑树(平衡操作详解)》

上述这种情况,找到新插入节点38的祖父节点25,以25为顶端,进行左旋转

    4)内侧子孙的旋转平衡术

《红黑树(平衡操作详解)》
        
上述这种情况,找到新插入节点22的父节点18,然后以18位顶端,进行左旋转,旋转后结果如下
《红黑树(平衡操作详解)》

然后以22的父节点25进行右旋转,旋转结果如下
《红黑树(平衡操作详解)》
        再修改22和18、25节点的颜色,即保持树的正确

    总结:外侧子孙和内侧子孙的平衡都是需要进行旋转,不同的是外侧子孙只需要进行一次旋转即可,而内侧子孙则需要进行两次旋转,第一次旋转后变成外侧子孙的模式,再根据外侧子孙的方式来进行平衡即可

3.插入新节点

    红黑树插入新节点的过程中,会遇到违背红黑树规则的情况,为了保持树的平衡,则需要使用以上的几种方式来保持树平衡

    下面介绍下以下几种插入新节点过程中遇到的问题及其解决方案:

    1)在下行过程中发现黑色节点下有两个红色子节点

        为什么这种情况是会违背红黑树规则呢?因为根据规则3,红色节点下的子节点必须为黑色节点,那么插入黑色子节点后就会违背规则4,所以碰到这种情况,需要对这三个节点进行颜色变换

《红黑树(平衡操作详解)》
当再插入12节点时,就会与18节点产生颜色冲突,所以需要对18 25 30三个节点进行颜色变换,变换成如下,再插入12节点即可

《红黑树(平衡操作详解)》

    

    2)插入节点后发生颜色冲突

        接着上个树来继续添加节点6

《红黑树(平衡操作详解)》

发现6节点和12节点都是红色,违背规则3,则根据上述外侧子孙节点处理方案对6的祖父节点18进行右转
《红黑树(平衡操作详解)》
此时12和25节点都是红色,同样违背规则3,对12的祖父节点50节点进行右转

《红黑树(平衡操作详解)》

再对上述节点颜色错误的进行颜色变换,25、12、6节点都变成黑色,即变成一颗复合规则的红黑树

《红黑树(平衡操作详解)》

    3)插入过程中发生颜色冲突
《红黑树(平衡操作详解)》
以上节点属于平衡状态,此时如果再插入节点3,则需要对12、6、18节点进行颜色变换操作

《红黑树(平衡操作详解)》

此时12和25节点又发生了颜色冲突,则需要找到12节点的祖父节点50,然后以50节点进行右旋转

《红黑树(平衡操作详解)》

再改变25和12的颜色为黑色,以符合规则2和4

《红黑树(平衡操作详解)》

此时已经平衡,再插入节点3即可,结果如下

《红黑树(平衡操作详解)》


    总结:针对于红红冲突,需要找到合适的祖父节点,然后进行旋转,再进行节点颜色变换,则就可以保持树的平衡

    至于代码实现,可以参考TreeMap

参考:Java数据结构和算法(第二版)

    原文作者:算法小白
    原文地址: https://blog.csdn.net/qq_26323323/article/details/79643216
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞