zoukankan      html  css  js  c++  java
  • 数据结构与算法——红黑树

    红黑树

      一、定义:

      红黑树是一个自平衡二叉查找树,平衡二叉树是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。作为二叉查找树,红黑树广泛的被应用于各种数据结构中,例如HashMap(jdk8之后),TreeMap。

      二、性质:

      为了实现红黑树的自平衡及二叉查找树的特点,红黑树具有如下性质:

    性质1. 节点是红色或黑色。
    性质2. 根节点是黑色。
    性质3. 每个叶节点(NIL节点,空节点)是黑色的。
    性质4. 每个红色节点的两个子节点都是黑色。
    性质5. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
       注意:4、5 两点保证了:从每个叶子到根的所有路径上不能有两个连续的红色节点,从而保证了最长分支不会超过最短分支长度的二倍

      三、红黑树的旋转:

    在红黑树构建过程中,为了维护红黑树的平衡性,会对树的节点进行左旋或右旋。为了更好的理解红黑树的构建,先用两组图片描述了典型的红黑树的左旋案例。理解了左旋也就理解了右旋的概念。
     

     

    四、红黑树构建:

        以下面这颗红黑树举例,演示节点增加和删除的过程:

    图1

    新增节点步骤

          1、将新增节点按照普通的二叉查找树插入到原来的红黑树中,并涂成红色。

          将图1的红黑树新增“节点12”,按照二叉查找树的特征,将此节点插入到“节点11”的右侧,形成如下图2新的树状结构,恰好此结构也保持了红黑树的特征,插入完成。

    图2

          2、通过重新涂色以及旋转将新的二叉查找树的树重新构建成红黑树。

          将红色新节点插入到红黑树中,可能会违背红黑树的那些性质?

    性质1. 节点是红色或黑色。(不会,因为插入的是红色节点)
    性质2. 根节点是黑色。(不会,按照二叉查找树的方式插入节点不会改变根节点。例外情况是空树,此种情况直接在算法最后将根节点涂成黑色即可)
    性质3. 每个叶节点(NIL节点,空节点)是黑色的。(不会,因为插入的是非空节点,而叶节点都是空节点)
    性质4. 每个红色节点的两个子节点都是黑色。(可能会)
    性质5. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。(不会,因为插入的是红色节点,不会改变路径上黑色节点的数目)
    那么,我们只需通过一定的方法使这棵树重新满足性质4即可,分析只有当新节点的父节点为红色节点时才会出现这种情况。
     

    处理新节点(以下称新节点为z)父节点为红色节点可能会遭遇三种情况,处理方案建立在z的父结点是左孩子基础上,相反情况判断方法及旋转方向均相反:

    情况1:z节点的叔父节点也为红色,此时祖父节点一定为黑色(否则违背了性质4),此时需要将z的父节点和叔父节点都染成黑色,祖父节点染成红色,z指向祖父节点。影响:不会对任何分支上的红黑节点数产生影响,单纯的是把z节点升高了两层。
    • 考虑我们将21节点插入图2的红黑树中:形成图3,z节点为21
    图3
        • 将父节点和叔父节点涂成黑色,祖父节点涂成红色,z指向祖父节点25:形成图4,z节点为25

    图4

        • 依然符合情况1,节点z的父节点与叔父节点均为红色,祖父节点黑色,将父节点及叔父节点均涂为黑色,祖父节点涂为红色,由于祖父节点为根节点,再涂为黑色形成新的红黑树,见图5

    图5 

    情况2:z节点的叔父节点为黑色,且z节点为右孩子,需要将z节点指向其父节点,再以新的z节点进行左旋。影响:将情况2转化为情况3

        • 考虑图5基础上(此处案例设计问题,将图5中的22改成23,结构保持不变)插入节点22,形成图6,z节点为22

    图6

        • 本身为红色,父节点为红色,叔父节点为黑色,且自身为右孩子节点,那么将z指向其父节点21节点,并以21节点进行左旋:形成图7,z节点为21。

    图7

    情况3:z的叔父节点是黑色的且z是一个左孩子,将z的父节点染黑,z的祖父节点染红,然后以z的祖父节点进行右旋。影响:在两次修改颜色后,会导致从根结点向左出发的所有路径的黑高不变,而向右出发的所有路径的黑高减1;而右旋操作会使黑高回归平衡。

        • 考虑图7,z节点为21,z的叔父节点22为黑色且z是一个左孩子,将z的父节点22染黑,z的祖父节点23染红:形成图8,z节点为21

    图8

        • 考虑图8,z节点为21,以z节点的祖父节点进行右旋,形成图9,此时红黑树重新形成。

     

    图9

    插入节点总结:

    情况1逐步提高z节点的层高,其导致的结果有两个。

      1、z节点升高到根节点,将根节点染黑后,整颗树回归红黑树特性;

      2、z节点的情况转化为3(直接转化为3或转化成2再转化成3)

    情况3执行过后会回归红黑树的特性。

    删除节点步骤(删除节点待补充示例图)

    1、将红黑树当成普通的二叉查找树,进行节点删除

          • 如果被删除的节点没有子节点,则直接删除
          • 如果被删除的节点只有一个子节点,则将此子节点顶替被删除节点的位置
          • 如果被删除的节点有两个子节点,则找到左子树的最大节点r(或者后继节点也可),将此节点的数据放入被删除的节点,同时删除节点r(因为r是左子树的最右节点,所以没有右节点,删除节点r可以转化成情况1或情况2)

    2、通过旋转和重新着色使二叉查找树恢复红黑树的特性

    分析:因为步骤1,可能会对红黑树的哪些特性产生影响?

    性质1. 节点是红色或黑色。(不会)
    性质2. 根节点是黑色。(会,但可以在算法着色最后,直接将红色根节点染黑就可以解决了)
    性质3. 每个叶节点(NIL节点,空节点)是黑色的。(不会)
    性质4. 每个红色节点的两个子节点都是黑色。(会)
    性质5. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。(会)
    现为被删除节点命名为N,经过步骤1的处理,N节点至多只有一个非空子节点。根据节点N颜色的不同可以分为以下两种情况
    • N节点为红色节点:那么N节点一定是有两个叶子节点(因为N节点为红色,那么其子节点一定为黑色,如果子节点一个是叶子节点一个是非空子节点,那么N节点左右子树包含的黑色节点个数不相等,违背了红黑树的特性),那么直接删除节点N即可。
    • N节点为黑色节点:可以分为两种情况,含有一个红色子节点或含有两个叶子节点(如果含有一个黑色的非空子节点,则左右分支黑色节点个数不等)

    1、N节点包含了一个红色非空子节点,则只需要把红色子节点顶替N节点,并涂成黑色(这样不会影响N节点以下各个分支黑色节点的个数),重新满足红黑树的特征;

    2、N节点包含了两个叶子节点,删除N节点后,代替N节点的为其NIL子节点,依然命名为N,该路径上的黑色节点比其他路径上的黑色节点个数少了一个,N节点的父节点命名为P,N的兄弟节点命名为B,则还需分为几种case(注意:以下case均以N是父结点P的左孩子结点,如果是右孩子结点,那么“左”和“右”应该对调):

    case1:N为根节点为根节点,因为N为NIL,则整颗树为空树,满足了红黑树的特征,结束。

    case2:N的兄弟节点为红色,则将P和B节点的颜色对调后,以P节点为支点进行左旋,然后进入case4、case5或case6

    case3:N、P、B三个节点都为黑色,则将B节点颜色涂为红色,此时P节点左右分支的黑节点数相等,但比不通过P节点的分支黑节点少一个,仍然需要按照这几个case继续处理P节点。

    case4:P位红色,N、B以及B的两个子节点都为黑色,则对调P和B的颜色,此时不影响通过B的黑色结点数量,但是在通过N的路径上增加了一个黑色结点,但是N节点会被删除后,满足了性质5.

    case5:B的左节点为红色,右节点为黑色,并且N为P的左孩子,则B与其左孩子颜色对调后右旋,此时进入case6

    case6:结点N的兄弟结点B是黑色的,B的右孩子是红色的(右红),并且结点N是父结点P的左孩子。此时将父结点P和兄弟结点S的颜色对调,再将S的右孩子变为黑色,然后左旋父结点P。

  • 相关阅读:
    Redis网络连接库剖析
    如何下载和安装pywin32
    Python游戏开发入门:pygame事件处理机制
    python常见错误
    波特率与比特率
    __gcd最大公约数
    动态规划算法之矩阵连乘问题
    二分插入排序+二分搜索
    office 总结
    javaWeb总结
  • 原文地址:https://www.cnblogs.com/qq455988971/p/8072047.html
Copyright © 2011-2022 走看看