zoukankan      html  css  js  c++  java
  • 平衡二叉树--红黑树(RB-Tree)

      关键字:修复双黑、插入修复、变色、旋转、nill、红黑
      前言:
                 自平衡方式--旋转

     
    1、定义:节点是黑色或者红色,且满足以下五条性质的自平衡二叉树
      性质
      (1)性质1:节点是红色或黑色
      (2)性质2:根节点是黑色的;
      (3)性质3:叶子节点是黑色的;
      (4)性质4:红色节点的子节点是黑色的;(红色节点不能相邻)
      (5)性质5:从根节点到任意一个叶子节点的路径上,黑色节点的个数必须相等(这个个数就称为黑高度 )。也就是说黑高度必须相等
     
      注意:
      (1)如果黑节点只有一个子节点,那么一定是红色的,因为如果是黑色的,那么会违反性质5;
      (2)从根节点到任何一个叶子节点的最长路径不超过最短路径的2倍。(最长路径=4);
      (3)新添加的节点是红色的。(如果插入的节点是黑色的,那么每次插入时都会违反性质5,所以默认插入节点是红色);
      (4)特殊节点--nil节点:(默认是黑色)
        ①相当于其他树结构中的NULL。在红黑树中,叶子节点指向nil节点,而不是指向NULL
        ②nil节点的父节点和右节点指向自己,其左节点指向根节点。如果没有根节点,那么它也指向自己;
        ③对于一个只有一个子节点的节点,它的另外一个子节点指向nil节点;
        ④根节点的父节点指向nil节点。
     
    2、红黑树维持平衡的方式:变色、旋转、五个性质约束。
     
    3、红黑树添加新节点:
    (1)找到插入节点的位置,然后插入节点;
    (2)判断此时的树是否满足红黑树的构成条件。如果满足那就万事大吉。如果不满足,那么进行“插入修复”。
    插入修复:
     
    情况1
    情况2
    情况3
    情况4
    情况
    插入的节点是根节点。
    插入的节点的父节点是黑色
    父节点:红色;
    叔叔节点:红色
    父节点:红色;
    叔叔节点:黑色。
    违反哪一条性质
    违反性质2;
    不会违反任何性质
    违反性质4
    违反性质4
    修复
    直接修改根节点为黑色
    不做任何操作
    将父节点和叔叔节点涂黑,将祖父节点涂红。
    将祖父节点作为当前节点。从当前节点重新进行插入修复
    将祖父节点作为当前节点。判断属于RR、RL、LL、LR的哪一种,然后进行相应的旋转操作。
    再将原来的父节点变黑;
    原来的祖父节点变红。
     注意:
      ①情况3和情况4都是要把节点上两层中的父层变成黑的,祖父变成红色。保证红红不相邻。而且是在调整结束之后再染色的;
      ②对于修复,一般就是在情况3/4之间来回处理;
      ③只要调整过程中,树能够满足红黑树的所有性质即可,那就不用继续调整了。
     
    4、红黑树删除节点:
    基础概念:
      双黑:删除节点和替换节点都是黑色的
      修复双黑:解决双黑情况下删除节点后导致红黑树不平衡的情况的一种调整策略
      前继节点:左子树中值最大的节点,中序遍历的前一个节点
      前续节点:左继节点的左孩子
      后继节点:右子树中值最小的节点。中序遍历的后一个节点
      后续节点:后继节点的右孩子
    (1)搜索删除节点;
    (2)查找替换节点;
      ①如果删除节点是叶子节点,那么替换节点就是nil;
      ②如果删除节点有一个子树,那么替换节点就是其前继或者后继节点;
      ③如果删除节点有两个孩子,那么中序遍历的后继节点就作为替换节点
      注意:替换节点一般是叶子节点或者nil节点。有的前继节点和后继节点不是叶子节点,比如左子树中只有左子树的节点,此时的前继节点不是叶子节点。如果替换节点还不是叶子节点,那么就还需要进行一步,也就是找到后续节点或者是前续节点。(此时的节点替换流程:删除节点先与后继节点交换,再与后续节点交换)
    (3)删除节点:
      ①如果有两个后代,那么交换替换节点和删除节点,然后对替换节点进行同样的删除操作;
      ②如果没有两个后代:
        a、删除节点是树根: 直接删除或者替换; 
        b、删除节点是叶子节点:因为替换节点是nil(黑色的),所以如果当前节点是黑色的,那么需要对当前节点进行修复双黑的相关操作;否则,直接删除即可
        c、如果有一个后代:与替换节点交换,然后再根据情况判断需不需要染黑当前节点(删除节点:替换节点---红:红、黑:红:染红; 红:黑:染黑)。如果是双黑,则进行修复双黑
     
    修复双黑:
    (1)没有兄弟:将双黑传递给父亲,也就是对父亲节点进行双黑修复;
    (2)存在兄弟:
      ①兄弟是红色:  “红父黑兄,兄转上”
              如果兄弟在右边,那么以父亲作为支点,进行左旋操作。然后染红父亲,染黑兄弟;
              如果兄弟在左边,那么以父亲作为支点,进行右旋操作。然后染红父亲,染黑兄弟;
      ②兄弟是黑色:
        a、兄弟没有红色孩子:
          染红兄弟;
          此时判断一下:父亲是红色的: 将父亲染黑;
                    父亲是黑色: 将双黑传递给父亲。
        b、兄弟有红色孩子:
      • 以父亲作为支点,判断和兄弟以及其孩子所构成的路径是直线型或者三角型
      • 对于三角型的,先转换成直线型的(RL->RR;LR->LL)
      • 此时,对于此时的删除节点,将其兄弟节点变父色;父亲和兄弟节点的儿子变成黑色;以父节点为支点进行旋转操作(左旋或者右旋,详见:自平衡方式--旋转
    注意:
    • 注意:是先进行修复双黑的,修复操作完全结束后再删除节点。所以这个过程中可能修复一次之后,还要再修复一次。反正就是等到修复完成之后,再删除节点。
    • 在修复的过程中是在调整结束之后再染色的。

     6、红黑树与普通二叉查找树:

      红黑树在每一次插入或删除节点之后都会花O(log N)的时间来对树的结构作修改,以保持树的平衡。也就是说,红黑树的查找方法与二叉搜索树完全一样;插入和删除节点的的方法前半部分节与二叉搜索树完全一样,而后半部分添加了一些修改树的结构的操作。
     

    参考资料:

    https://blog.csdn.net/maihilton/article/details/79900770

    https://www.bilibili.com/video/av53772633/?p=1

    https://www.bilibili.com/video/av45909616?share_medium=android&share_source=qq&bbid=PgY2B2FQY1E1UGIHewd7infoc&ts=1564714726372

  • 相关阅读:
    Leetcode 92. Reverse Linked List II
    Leetcode 206. Reverse Linked List
    Leetcode 763. Partition Labels
    Leetcode 746. Min Cost Climbing Stairs
    Leetcode 759. Employee Free Time
    Leetcode 763. Partition Labels
    搭建数据仓库第09篇:物理建模
    Python进阶篇:Socket多线程
    Python进阶篇:文件系统的操作
    搭建数据仓库第08篇:逻辑建模–5–维度建模核心之一致性维度2
  • 原文地址:https://www.cnblogs.com/axing-articles/p/11402620.html
Copyright © 2011-2022 走看看