根据定义理解红黑树插入删除调整

红黑树简介:

R-B Tree,全称是Red-Black Tree,又称为“红黑树”,是一种特殊的二叉查找树。红黑树的每个结点上都有存储位表示结点的颜色,可以是红(Red)或黑(Black)。

红黑树的定义:

  1. 每个结点是黑色或者红色。
  2. 根结点是黑色。
  3. 每个叶子结点(NIL)是黑色。 [注意:这里叶子结点,是指为空(NIL或NULL)的叶子结点!]
  4. 如果一个结点是红色的,则它的子结点必须是黑色的。
  5. 每个结点到叶子结点NIL所经过的黑色结点的个数一样的。[确保没有一条路径会比其他路径长出俩倍,所以红黑树是相对接近平衡的二叉树的!]

注:源码来源:JDK1.8 TreeMap

插入

红黑树插入方式与二叉树插入一致,只是多了一步调整。

插入调整:

前提条件:插入节点的父节点是红色时,需要调整(不满足定义4)。

private void fixAfterInsertion(Entry<K,V> x) {
     //默认插入节点为红色
        x.color = RED; 
        while (x != null && x != root && x.parent.color == RED) {
             左插:插入节点的父节点是爷爷节点的左孩子
            if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {
                代码1:
                Entry<K,V> y = rightOf(parentOf(parentOf(x)));
                代码2if (colorOf(y) == RED) {
                    setColor(parentOf(x), BLACK);
                    setColor(y, BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    x = parentOf(parentOf(x));
                } else {
                    代码3if (x == rightOf(parentOf(x))) {
                        x = parentOf(x);
                        rotateLeft(x);
                    }
                    代码4:
                    setColor(parentOf(x), BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    rotateRight(parentOf(parentOf(x)));
                }       
            } 
              右插:插入节点的父节点是爷爷节点的右孩子,与左插对称
            else {
                Entry<K,V> y = leftOf(parentOf(parentOf(x)));
                if (colorOf(y) == RED) {
                    setColor(parentOf(x), BLACK);
                    setColor(y, BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    x = parentOf(parentOf(x));
                } else {
                    if (x == leftOf(parentOf(x))) {
                        x = parentOf(x);
                        rotateRight(x);
                    }
                    setColor(parentOf(x), BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    rotateLeft(parentOf(parentOf(x)));
                }
            }
        }
        root.color = BLACK;
    }

定义插入节点为 c,插入节点父节点为(父节点) p(红色) ,插入节点父节点的兄弟节点为(叔叔节点) u,插入节点的爷爷节点为g。

代码1:

插入节点c(默认为红色)插入后,不满足定义4,所以已u为入点调整树。

代码2: 调整点u为红色

​ 先将p,u置为黑色,g置为红色。在将g节点视为插入点递归调整。

理解:

前提可知: p,u 是红色,若u是红色,根据定义4可得g是黑色。

​插入后,为了满足定义4,定义5,将p,u置为黑色,g置为红色,保证左右子树每个分支黑色节点个数与插入前相同。
但变色后可能存在g的父节点是红色的情况下,例如图1.1 插入7,变色后得图1.2 ,g对于节点10,不满足定义4。所以将g做为新的插入点。

图1.1:

在这里插入图片描述

图1.2

在这里插入图片描述

代码3:

调整点u为黑色,插入节点c为父节点p的右孩子,此时将p设置为插入点 ,并左旋。

图1.3:

在这里插入图片描述

例如图1.3 此时插入节点5,形状类似 ‘ < ’,需要旋转变为‘ / ’。旋转后将4当做新插入点。

图1.4:

在这里插入图片描述

代码4:

调整点u为黑色(可能为null),先变色,在旋转。

​ 理解:

调整点u为空的情况,例如图1.3,此时插入2,不满足定义4,变色;变色后,不满足定义5,旋转。

调整点u不为空的情况,例如图1.4,此时插入9,此时p为黑色,这种情况不满足插入调整,不必调整。

对于图1.3,此时插入2。可得:

在这里插入图片描述

节点4为黑色,即使4存在父节点,必能满足定义4,且调整后分支黑色节点个数没有发生改变,必能满足定义5,所以结束调整。

插入总结:
​ 1、先把插入节点的父亲的兄弟节点做为初始调整点。
​ 2、若调整点为红色,先做变色,将在爷爷节点做为调整点循环调整。
​ 3、若调整点为黑色,先把插入后树形状 为 ‘< >’,处理为 ‘ / \ ’并变色。
​ 4、变色旋转,结束调整。
​ 5、 循环结束后,将根节点变为黑色。

删除

二叉树删除

  1. 删除节点有一个孩子,用子孩子顶替删除节点。
  2. 删除节点没有子孩子,直接用null节点顶替删除节点。
  3. 删除节点有两个子孩子,找到删除节点的前驱或后继节点( 左子树下最大的节点或者右子树下最小的节点 ),将前驱或后继节点的值赋给删除节点,并做为新的删除节点。

红黑树删除多一步调整。

删除调整

前提:删除节点不是根节点,并且颜色为黑色(不满足定义5)

 private void fixAfterDeletion(Entry<K,V> x) {
        while (x != root && colorOf(x) == BLACK) {
            左删: 删除节点为父节点的左孩子
            if (x == leftOf(parentOf(x))) {
                 代码1
                Entry<K,V> sib = rightOf(parentOf(x));
                 代码2
                if (colorOf(sib) == RED) {
                    setColor(sib, BLACK);
                    setColor(parentOf(x), RED);
                    rotateLeft(parentOf(x));
                    sib = rightOf(parentOf(x));
                }

                代码3
                if (colorOf(leftOf(sib))  == BLACK &&
                    colorOf(rightOf(sib)) == BLACK) {
                    setColor(sib, RED);
                    x = parentOf(x);
                } else {
                     代码4 
                    if (colorOf(rightOf(sib)) == BLACK) {
                        setColor(leftOf(sib), BLACK);
                        setColor(sib, RED);
                        rotateRight(sib);
                        sib = rightOf(parentOf(x));
                    }
                    代码5
                    setColor(sib, colorOf(parentOf(x)));
                    setColor(parentOf(x), BLACK);
                    setColor(rightOf(sib), BLACK);
                    rotateLeft(parentOf(x));
                    x = root;
                }
            }
             右删:删除节点为父节点的右孩子 与左删对称
            else { 
                Entry<K,V> sib = leftOf(parentOf(x));

                if (colorOf(sib) == RED) {
                    setColor(sib, BLACK);
                    setColor(parentOf(x), RED);
                    rotateRight(parentOf(x));
                    sib = leftOf(parentOf(x));
                }

                if (colorOf(rightOf(sib)) == BLACK &&
                    colorOf(leftOf(sib)) == BLACK) {
                    setColor(sib, RED);
                    x = parentOf(x);
                } else {
                    if (colorOf(leftOf(sib)) == BLACK) {
                        setColor(rightOf(sib), BLACK);
                        setColor(sib, RED);
                        rotateLeft(sib);
                        sib = leftOf(parentOf(x));
                    }
                    setColor(sib, colorOf(parentOf(x)));
                    setColor(parentOf(x), BLACK);
                    setColor(leftOf(sib), BLACK);
                    rotateRight(parentOf(x));
                    x = root;
                }
            }
        }

     代码6
        setColor(x, BLACK);
    }

定义删除节点为 d,删除节点父节点为 p,删除节点的兄弟节点为 b。

代码1

删除d,根据定义5,直接影响p的左右子树黑色节点个数不平衡,b子树的黑色节点个数多余,所以将b做为初始的调整点。

代码2

调整点b位红色, 先将b置为黑色,p置为红色,围绕p右旋。后将p的右孩子做为新的调整点。

理解:
前提可知:b节点为红色,根据定义4,可得p节点和b的左右孩子为黑色。(d为黑色,删除前,必定满足定义5,即p的子树中必有黑色节点存在,又因b为红色,为满足定义4,b的左右孩子必存在且为黑色。)例如图2.1删除节点4。

d删除后,不满足定义5,所以将b置为黑色,p置为红色,围绕p右旋(旋转后b的左孩子变为p的右孩子)。相当于将b顶替p,并分了一个黑色节点的左孩子给p的右子树,弥补d的删除。
但旋转后,p左孩子为空,右孩子为黑色,不满足定义5,p右子树黑色节点多余,所以将p的右孩子做为新的调整点。

例如图2.1删除节点4,变色旋转后得图2.2,此时p对应节点8,将节点9做为新的调整点。(相当于把调整点为红色的情况转化调整点为黑色的情况,如图2.2 ,想象下删除节点4的情况

图2.1

在这里插入图片描述

图2.2

在这里插入图片描述

代码3

调整点b为黑色,且调整点b左右孩子为黑色,将b置为红色,并将p做为新的删除点。

理解:
前提可知:到代码3这里,b的颜色一定是黑色(在代码2处被调整),由于d是黑色,为满足定义5,所以这里b没有黑色的子孩子(若b有子节点也一定是红色)。

此时只能将b置为红色,让p的左右子树先满足定义5,并将p做为新的删除点向上调整。

此时p的颜色2种考虑:

p的颜色若为红色,如图2.3,删除节点9 ,最终在代码6出被调整;
p的颜色若为黑色,如图2.4,删除节点12,将25变红后,不满足定义5,要将23做为新的删除点向上调整。

图2.3

在这里插入图片描述

图2.4

在这里插入图片描述

代码4

调整点b的右孩子置为黑色,调整点b置为红色,并绕调整点右旋,将调整点b的右孩子置为新的调整点。

理解:
前提可知:经过代码2,代码3,b为黑色,且b至少有1个孩子且为红色。

若b的右孩子为黑色,必为空(代码4处已说明),则b的左孩子一定为红色节点,删除d后,树的形状为‘>’,所以要先变色旋转,变为‘ \ ’。例如如2.5 删除节点7,此时9-13-12 形状为‘ >’ 。

图2.5

在这里插入图片描述

代码5

将调整u置为p的颜色,将p与u的右孩子置为黑色,在绕p左旋,结束调整。

理解:此处做法是用调整点u顶替p,p顶替删除节点d,主要目的是为了满足定义5,让删除前后分支黑色节点个数没有变化。。

例如图2.6 删除7 的图2.7 ,删除前后分支黑色节点个数没有变化,所以结束调整。

图2.6

在这里插入图片描述

图2.7

在这里插入图片描述

删除总结:

1. 将删除节点的兄弟节点做为调整点(可能为红色,可能为黑色)。
2. 将调整点为红色的情况转化为调整点为黑色的情况,继续调整。
3. 将调整点无孩子的情况,变色,取父节点位新的删除点,向上循环调整。
4. 将调整点有孩子的情况,删除后调整点部分形状类似 ‘> ’ '< ',先做变色,旋转变为 ‘ \ ’ ’ / '。
5. 变色旋转,结束调整。

6. 删除点置为黑色。

参考

红黑树原理和算法介绍
红黑树 删除调整步骤终极详解
红黑树演示

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值