红黑树的查询,新增和删除,总结

红黑树定义和性质

红黑树是一种含有红黑结点并能自平衡的二叉查找树。它必须满足下面性质:

  • 性质1:每个节点要么是黑色,要么是红色。
  • 性质2:根节点是黑色。
  • 性质3:每个叶子节点(NIL||Null)是黑色。
  • 性质4:每个红色结点的两个子结点一定都是黑色。
  • 性质5:任意一结点到每个叶子结点的路径都包含数量相同的黑结点。

从性质5又可以推出:

  • 性质5.1:如果一个结点存在黑子结点,那么该结点肯定有两个子结点

红黑树不是完美平衡的二叉树。

img

造成这种不完美平衡的是中间的红色节点,根据性质5我们知道任意一个结点到到每个叶子结点的路径都包含数量相同的黑结点,所以红黑树的平衡是黑色完美平衡

红黑树的自平衡靠的是三种操作:左旋,右旋,变色。

左旋:以某个结点作为支点(旋转结点),其右子结点变为旋转结点的父结点,右子结点的左子结点变为旋转结点的右子结点,左子结点保持不变。如图3。

右旋:以某个结点作为支点(旋转结点),其左子结点变为旋转结点的父结点,左子结点的右子结点变为旋转结点的左子结点,右子结点保持不变。如图4。

变色:结点的颜色由红变黑或由黑变红。

img

img

左旋只影响旋转结点和其右子树的结构,把右子树的结点往左子树挪了。
右旋只影响旋转结点和其左子树的结构,把左子树的结点往右子树挪了。

左旋

这里写图片描述

红黑树的查找

红黑树的查找与二叉平衡树一样,由于红黑树始终是黑色平衡的,所以最坏的情况就是查找路线是红黑相间的情况时,时间复杂度为O(2lgN)

img

红黑树插入

img

当找到插入位置时,插入的是红色节点,因为如果插入黑色节点,那么插入位置所在的子树就永远是黑色节点多1的情况,始终要进行自平衡。

红黑树中的插入,除了更换相同的key的value值外,都是在叶子节点插入

img

情况1:红黑树为空树

这种情况直接插入到根节点就行,然后通过变色将插入节点变为黑色。因为红黑树根节点必须是黑色。(性质2)

  • 把插入结点作为根结点,并把结点设置为黑色
情况2:插入节点的key存在

这种情况不改变当前节点颜色,直接更新对应节点的value值即可。

  • 把I设为当前结点的颜色
  • 更新当前结点的值为插入结点的值
情况3:插入节点的父节点是黑色节点。

因为红黑树的平衡是黑色平衡,所以这种在黑色节点下面插入红节点不会违背红黑树的性质。

  • 直接插入
情况4:插入节点父节点是红色节点

这种情况就是红黑树的主要要讨论的情况了。因为根节点是黑色,所以父节点是红色时,插入节点必定有祖父节点。所以必定可以进行左旋or右旋。

情况4.1:叔叔节点为红节点

这种情况说明父亲和叔叔节点所在的子树这一层两个都是红节点,说明此时为黑红红的结构,这个时候最简单的就是将其变为红黑红的结构。

img

  • 将P和S设置为黑色
  • 将PP设置为红色
  • 把PP设置为当前插入结点

但是此时存在可能,即PP是根节点的情况,此时我们必须把PP设置为黑色,那么此时为黑黑红的结构,也就意味着黑色的层数增加了一层。这是唯一一种增加红黑树黑色节点层数的情景。我们不难发现,如果此时PP不是根节点,而是依然为红黑红的结构,那么由于性质4指出,红节点的子节点必须是黑色,所以我们要向上去做平衡变色处理,一直到根节点,使整个树满足红黑树的基本性质。**这证明红黑树是自底向上生长的。**普通二叉树都是自顶向下生长。

情景4.2:叔叔节点不存在,或者为叶子节点,并且插入节点的父节点为祖父节点的左子节点时。

听起来很绕,但是其实仔细看不难,首先看为什么把叔叔节点不存在与叔叔节点为叶子节点分为一种情况,因为如果只看插入前的情况,即忽略4.1中向上遍历的情况,叔叔节点是红色的情况上面已经讨论过了,那么叔叔节点是黑节点可能吗,这种情况必然会导致叔叔节点下面的叶子节点比父节点下面的叶子节点到根节点所经过的黑色节点多一个,所以如果叔叔节点为黑节点,那么叔叔节点必须是叶子节点。

情况4.2.1:插入节点为父节点的左子节点。

  • 将P设为黑色
  • 将PP设为红色
  • 对PP进行右旋

img

此时进行了右旋,因为P下面I为红色,不符合定义,此时可以思考,P在右旋后设为红色的情况,也是可以的,但是这就加入了额外的操作,不划算。

情况4.2.2:插入节点是父节点的右子节点

  • 对P进行左旋
  • 把P设置为插入结点,得到情景4.2.1
  • 进行情景4.2.1的处理

img

这是一个需要双旋的情况,可以参考下图:

avlæ ‘æ—‹è½¬çš„å›¾å½¢æè¿°ã€‚

事实上就是转化到4.2.1的情况。

情况4.3:叔叔节点不存在或为叶子节点,并且插入节点的父亲节点是祖父节点的右子节点。

与情况4.2一样。

情况4.3.1:插入节点是父节点的右子节点

  • 将P设为黑色
  • 将PP设为红色
  • 对PP进行左旋

img

情况4.3.2:插入节点是父节点的左子节点

  • 对P进行右旋
  • 把P设置为插入结点,得到情景4.3.1
  • 进行情景4.3.1的处理

img

红黑树删除

所有的树都会有插入和删除操作,而删除操作无外乎两个步骤:

  1. 查找目标节点
  2. 删除后自平衡

不存在要删除的节点时,忽略删除操作;存在要删除节点时,删除并进行自平衡处理。

普通二叉树的删除操作为:

  • 情景1:若删除节点无子节点,直接删除

img

图中我们可以直接删除12.

  • 情景2:若删除节点只有一个子节点,用子节点替换删除节点

img

图中删除13,然后以11代替,11的子节点结构不变。

img

  • 情景3:若删除节点有两个子节点,用后继节点(仅大于删除节点的节点)替换删除节点

img

img

img

情景3习惯上都是用仅大于删除节点的节点去替换。(也可以用仅小于删除节点的节点去替换)

img

删除操作删除的结点可以看作将替代节点复制到被删除节点处,然后删除替代结点,而替代结点最后总是在树末。

接下来我们分析所有情况

img

R表示替代结点,P表示替代结点的父结点,S表示替代结点的兄弟结点,SL表示兄弟结点的左子结点,SR表示兄弟结点的右子结点。灰色结点表示它可以是红色也可以是黑色。

R是即将被替换到删除结点的位置的替代结点,在删除前,它还在原来所在位置参与树的子平衡,平衡后再替换到删除结点的位置,才算删除完成。

情况1:替换节点是红色节点

这种情况最简单,直接删除掉替换节点即可,不会影响红黑树平衡。

  • 颜色变为删除结点的颜色
情况2:替换节点是黑色节点

如果替换节点时黑色节点,那么删除替换节点必然会影响子树的平衡,因此必须做自平衡处理。

情况2.1:替换节点时其父节点的左子节点

情况2.1.1:替换节点的兄弟节点是红节点

若兄弟节点是红色节点,那么父节点和兄弟节点的子节点必定是黑色。所以

  • 将S设为黑色
  • 将P设为红色
  • 对P进行左旋,得到情景2.1.2.3
  • 进行情况2.1.2.3的处理

img

情况2.1.2:替换节点的兄弟节点是黑色

兄弟节点为黑,则无法确定父节点和子节点的颜色。

情况2.1.2.1:替换节点的兄弟节点的右子节点是红色,左子节点为任意颜色

替换节点是黑色,删除后左子树少一个黑色节点,那么必须从右子树借一个黑色节点,则必须左旋。

  • 将S的颜色设为P的颜色
  • 将P设为黑色
  • 将SR设为黑色
  • 对P进行左旋

img

删除R则无影响。

情况2.1.2.2:替换节点的兄弟节点的右子节点为黑色,左子节点为红色。

若删除R则必须从右节点借一个红色节点才能不影响平衡,所以考虑将情况2.1.2.2转换为情况2.1.2.1。

  • 将S设为红色
  • 将SL设为黑色
  • 对S进行右旋,得到情景2.1.2.1
  • 进行情景2.1.2.1的处理

img

情况2.1.2.3:替换节点的兄弟节点的子节点都是黑色

这种情况没有兄弟的红色节点借给你了,所以必须要找别的地方拿红节点,那么由红黑树是自底向上生长的性质我们想到,可以和增加节点一样,将P作为新的替换节点,但是实际删除的还是R。只是把P当作是替换节点去自底向上的重复上述情况处理。

  • 将S设为红色
  • 把P作为新的替换结点
  • 重新进行删除结点情景处理

img

情况2.2:替换节点是其父节点的右子节点

同理情况2.1,这是以前继节点作为替换节点进行处理。

情况2.2.1:替换节点的兄弟节点是红色

  • 将S设为黑色
  • 将P设为红色
  • 对P进行右旋,得到情景2.2.2.3
  • 进行情景2.2.2.3的处理

img

情况2.2.2:替换节点的兄弟节点是黑色

情况2.2.2.1:替换节点的兄弟节点的左子节点是红节点,右子节点任意颜色

  • 将S的颜色设为P的颜色
  • 将P设为黑色
  • 将SL设为黑色
  • 对P进行右旋

img

情况2.2.2.2:替换节点的兄弟节点的左子节点为黑色,右子节点为红色

  • 将S设为红色
  • 将SR设为黑色
  • 对S进行左旋,得到情景2.2.2.1
  • 进行情景2.2.2.1的处理

img

情况2.2.2.3:替换节点的兄弟节点的子节点都是黑色

  • 将S设为红色
  • 把P作为新的替换结点
  • 重新进行删除结点情景处理

img

总结

红黑树的优点在于其利用变色的操作,节省了大量的左旋or右旋操作,加快了新增删除的速度,所以HashMap的实现在元素小于8个的时候采用AVL树,因为此时认为新增删除成本小于查询成本,而大于8个时就切换为了红黑树。

但是与AVL树相比,红黑树的时间复杂度更高,最坏情况下达到O(2logN),因为红黑树是黑平衡,而不是整体的高度平衡,所以查找速度慢于AVL树。

与B树,B+树相比,红黑树多用于内部排序,即存在内存中,STL的map和set的内部实现就是红黑树。而B树,B+树利用的是m叉树结构,所以高度远小于红黑树以及AVL树,所以B+树一般用于外存来减少I/O操作的次数,而且所有关键字的查询路径长度相同,所以B+树效率更加稳定。

参考:https://www.jianshu.com/p/86a1fd2d7406
https://www.jianshu.com/p/e136ec79235c
https://zhuanlan.zhihu.com/p/143396578

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值