zoukankan      html  css  js  c++  java
  • 红黑树(平衡操作详解)

    摘自 https://blog.csdn.net/qq_26323323/article/details/79643216
     
     
     
    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数据结构和算法(第二版)
  • 相关阅读:
    算法第五章作业
    第四章实验报告
    算法第三章作业
    算法第三章上机实验报告
    算法第二章作业
    算法第二章上机实践报告
    算法 代码规范(C++)&《数学之美》读后感
    第七章学习小结
    第六章学习小结
    第五章学习小结
  • 原文地址:https://www.cnblogs.com/zzt-lovelinlin/p/9483062.html
Copyright © 2011-2022 走看看