一文彻底弄懂红黑树

一、什么是红黑树

红黑树是一种自平衡的二叉查找树,是一种高效的查找树。它是由 Rudolf Bayer 于1972年发明,在当时被称为对称二叉 B 树(symmetric binary B-trees)。后来,在1978年被 Leo J. Guibas 和 Robert Sedgewick 修改为如今的红黑树。

  • 红黑树具有良好的效率,可以保证在最坏的情况下基本动态集合操作(查找、插入、删除等)的时间复杂度为O(logN)
  • 红黑树在业界应用很广泛,比如 Java 中的 TreeMapJDK 1.8 中的 HashMapC++ STL 中的 map以及Linux虚拟内存的管理均是基于红黑树结构实现的。

二、红黑树性质

对于普通的二叉查找树,在极端的情况下会变成链表形式,比如顺序插入一系列值,这样会导致查找效率近似等于O(N),效率低下。因此就出现了一些自平衡的查找树,比如 AVL,红黑树等。这些自平衡的查找树通过定义一些性质,将任意节点的左右子树高度差控制在规定范围内,以达到平衡状态

红黑树的性质如下

  • 1)每个节点要么是红色,要么是黑色
  • 2)根节点是黑色
  • 3)每个叶子节点是黑色(这里的叶子节点指的是为空(NIL或NULL)的叶子节点)
  • 4)如果一个节点是红色的,那么它的子节点必须是黑色的(即不存在两个红色节点相连)
  • 5)从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点(简称黑高)

上图就是一个典型的红黑树结构,从根节点0080到每个叶子节点的路径中,黑色节点数始终为3,即黑高为3。没有两个连续的红色节点。(这里的图使用了一个数据结构可视化的网站,里面包含常见数据结构可视化过程,地址为:t.cn/RZFgryr)。

三、红黑树的自我修正

红-黑树主要通过两种方式对平衡进行修正,变色和旋转。(以下的示例图忽略了空叶子节点)

1. 改变节点颜色

  • 1)初始状态

  • 2)新插入节点10,一般新插入的节点颜色均为红色

  • 3)此时需要改变颜色,故将10的父节点15和父节点15的兄弟节点68由红色变为黑色,节点15和节点68的父节点由黑色变为红色,并以此递归向上调整。

  • 4)节点30为根节点,根节点必须为黑色,因此需要恢复为黑色

全部流程如下动图所示

2. 旋转

旋转又分为左旋和右旋操作,左旋是将某个节点旋转为其右孩子的左孩子,而右旋是节点旋转为其左孩子的右孩子,如下图所示

  • 左旋操作流程
    • 1)将节点B的右孩子引用指向节点D的左孩子
    • 2)将节点D的左孩子引用指向节点B,完成左旋操作
  • 右旋操作流程
    • 1)将节点D的左孩子引用指向节点B的右孩子
    • 2)将节点B的右孩子引用指向节点D,完成右旋操作

引用网上的两个动图更清晰一点

  • 左旋

  • 右旋

四、红黑树的操作

1. 插入操作

红黑树的插入过程和二叉查找树插入过程基本类似,不同的地方在于,红黑树插入新节点后,需要进行调整,以满足红黑树的5个性质。另外红黑树在插入时,新节点固定是红色的。为什么一定是红色的呢?可以反过来理解,如果新节点为黑色,那么这个节点所在的路径一定会比其他路径多出一个黑色节点,为了满足红黑树的性质,必须进行大规模的调整。相反如果是红色的,那么就不会打破黑高一致的性质,仅仅可能会出现连续两个红色节点的问题,这种情况下调整只需要进行变色和旋转即可

考虑到红黑树的各种情况,插入操作一共可分为以下五种情况。注:在下面的讨论中,使用N,P,G,U表示关联的节点。N(now)表示当前节点,P(parent)表示N的父节点,U(uncle)表示N的叔叔节点,G(grandfather)表示N的祖父节点,也就是P和U的父节点。

  • 1)情况一:第一次插入

    这种情况直接将该节点作为根节点,并且涂黑即可

  • 2)情况二:插入节点的父节点是黑色的

    这种情况下没有违背红黑树的规则,无需处理

  • 3)情况三:插入节点的父节点是红色的,其叔叔(祖父节点的另一个子节点)节点也是红色的

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    N的父节点是红色(节点 P 为红色,其父节点必然为黑色),叔叔节点 U 也是红色。由于 P 和 N 均为红色,不满足红黑树性质4,此时需要进行调整。这种情况下,先将 P 和 U 的颜色染成黑色,再将 G 的颜色染成红色。此时经过 G 的路径上的黑色节点数量不变,性质5仍然满足。但需要注意的是 G 被染成红色后,可能会和它的父节点形成连续的红色节点,此时需要递归向上调整如果G根节点,则需染成黑色

  • 4)情况四:插入节点的父节点是红色的,叔叔节点是黑色的,且插入节点是其父节点的右子节点

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    N 的父节点为红色,叔叔节点为黑色。节点 N 是 P 的右孩子,且节点 P 是 G 的左孩子。此时先对节点 P 进行左旋,调整 N 与 P 的位置,接下来按照情况五进行处理,以恢复性质4。注意:

  • 5)情况五:插入节点的父节点是红色的,叔叔节点是黑色的,且插入节点是其父节点的左子节点

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

N 的父节点为红色,叔叔节点为黑色。N 是 P 的左孩子,且节点 P 是 G 的左孩子。此时对 G 进行右旋,调整 P 和 G 的位置,并互换颜色。经过这样的调整后,性质4被恢复,同时也未破坏性质5。

2. 删除操作

相较于插入操作,红黑树的删除操作则要更为复杂一些。删除操作首先要确定待删除节点有几个孩子,如果有两个孩子,不能直接删除该节点。而是要先找到该节点的前驱(该节点左子树中最大的节点)或者后继(该节点右子树中最小的节点),然后将前驱或者后继的值复制到要删除的节点中,最后再将前驱或后继删除。由于前驱和后继至多只有一个孩子节点,这样我们就把原来要删除的节点有两个孩子的问题转化为只有一个孩子节点的问题,问题被简化了一些。我们并不关心最终被删除的节点是否是我们开始想要删除的那个节点,只要节点里的值最终被删除就行了,至于树结构如何变化,这个并不重要。

红黑树删除操作的复杂度在于删除节点的颜色,当删除的节点是红色时,直接拿其孩子节点补空位即可。因为删除红色节点,性质5(从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点)仍能够被满足。当删除的节点是黑色时,那么所有经过该节点的路径上的黑节点数量少了一个,破坏了性质5。如果该节点的孩子为红色,直接拿孩子节点替换被删除的节点,并将孩子节点染成黑色,即可恢复性质5。但如果孩子节点为黑色,处理起来就要复杂的多。分为6种情况,下面会展开说明。

在展开说明之前,我们先做一些假设,方便说明。这里假设最终被删除的节点为X(至多只有一个孩子节点),其孩子节点为NX的兄弟节点为SS的左节点为 SL,右节点为 SR。接下来讨论是建立在节点 X 被删除,节点 N 替换X的基础上进行的。

在上面的基础上,接下来就可以展开讨论了。红黑树删除有6种情况,分别是:

  • 情况一

    要删除的节点 X 是根节点,且左右孩子节点均为空节点,此时将节点 X 用空节点替换完成删除操作。

  • 情况二

    S 为红色,其他节点为黑色。这种情况下可以对 N 的父节点进行左旋操作,然后互换 P 与 S 颜色。但这并未结束,经过节点 P 和 N 的路径删除前有3个黑色节点(P -> X -> N),现在只剩两个了(P -> N)。比未经过 N 的路径少一个黑色节点,性质5仍不满足,还需要继续调整。不过此时可以按照情况四、五、六进行调整

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 情况三

    N 的父节点,兄弟节点 S 和 S 的孩子节点均为黑色。这种情况下可以简单的把 S 染成红色,所有经过 S 的路径比之前少了一个黑色节点,这样经过 N 的路径和经过 S 的路径黑色节点数量一致了。但经过 P 的路径比不经过 P 的路径少一个黑色节点,此时需要从情况一开始对 P 进行平衡处理。

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 情况四

    N 的父节点是红色,S 和 S 孩子为黑色。这种情况比较简单,我们只需交换 P 和 S 颜色即可。这样所有通过 N 的路径上增加了一个黑色节点,所有通过 S 的节点的路径必然也通过 P 节点,由于 P 与 S 只是互换颜色,并不影响这些路径。

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 情况五

    S 为黑色,S 的左孩子为红色,右孩子为黑色。N 的父节点颜色可红可黑,且 N 是 P 左孩子。这种情况下对 S 进行右旋操作,并互换 S 和 SL 的颜色。此时,所有路径上的黑色数量仍然相等,N 兄弟节点的由 S 变为了 SL,而 SL 的右孩子变为红色。接下来我们到情况六继续分析。

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 情况六

    S 为黑色,S 的右孩子为红色。N 的父节点颜色可红可黑,且 N 是其父节点左孩子。这种情况下,我们对 P 进行左旋操作,并互换 P 和 S 的颜色,并将 SR 变为黑色。因为 P 变为黑色,所以经过 N 的路径多了一个黑色节点,经过 N 的路径上的黑色节点与删除前的数量一致。对于不经过 N 的路径,则有以下两种情况:

    • 1)该路径经过 N 新的兄弟节点 SL ,那它之前必然经过 S 和 P。而 S 和 P 现在只是交换颜色,对于经过 SL 的路径不影响。
    • 2)该路径经过 N 新的叔叔节点 SR,那它之前必然经过 P、 S 和 SR,而现在它只经过 S 和 SR。在对 P 进行左旋,并与 S 换色后,经过 SR 的路径少了一个黑色节点,性质5被打破。另外,由于 S 的颜色可红可黑,如果 S 是红色的话,会与 SR 形成连续的红色节点,打破性质4(每个红色节点必须有两个黑色的子节点)。此时仅需将 SR 由红色变为黑色即可同时恢复性质4和性质5(从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点)

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

转载地址

红黑树详细分析,看了都说好

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值