红黑树详解

二叉搜索树
二叉搜索树又叫二叉查找树、二叉排序树,其特点如下所述:

  1. 节点的左子树小于节点本身;
  2. 节点的右子树大于节点本身;
  3. 左右子树同样为二叉搜索树。
    下图就是一棵典型的二叉搜索树:典型的二叉搜索树
    二叉搜索树是均衡二叉树的基础,我们看一下它的搜索步骤如何。我们要从二叉树中找到值为58的节点。

step1:首先查找到根节点,值为60的节点。
在这里插入图片描述
step2:比较我们要找的值58与该节点的大小。
如果等于,那么恭喜,已经找到;如果小于,则继续找左子树;如果大于,那么找右子树。
很明显 58 < 60,因此我们找到左子树的节点56,此时我们已经定位到了节点56。
在这里插入图片描述
step3:按照第二步的规则继续找。
58 > 56,所以我们需要继续找右子树,定位到了右子树节点58,恭喜,此时我们已经找到了。
在这里插入图片描述
我们经过上述三步就已经找到了所需的节点,其实就是我们平时所说的二分查找,看上去这种二叉搜索树好像查找效率很高,但同样它也有着缺陷,比如下面这样的二叉搜索树:
在这里插入图片描述
如果我们要对其找值为50的节点,那基本上和单链表查询没多大区别了,性能将大打折扣。这个时候我们的均衡二叉树就粉墨登场了,均衡二叉树就是在二叉搜索树的基础上添加了自动维持平衡的性质。上面的二叉搜索树经过自动平衡后,可能就成为了下面这样的二叉树:
在这里插入图片描述
经过了自动平衡,再去找值为50的节点,查找性能将提升很多。红黑树就是非严格均衡的二叉搜索树,均衡二叉树又是在二叉搜索树的基础上增加了自动维持平衡的性质,插入、搜索、删除的效率都比较高。红黑树的使用非常广泛,如TreeMap和TreeSet都是基于红黑树实现的,而 JDK 8 中HashMap当链表长度大于8时也会转化为红黑树。

红黑树

  1. 节点分为红色或者黑色;
  2. 根节点必为黑色;
  3. 叶子节点都为黑色,且都为null;
  4. 连接红色节点的两个子节点都为黑色(红黑树不会出现相邻的红色节点);
  5. 从任意节点出发,到其每个叶子节点的路径中包含相同数量的黑色节点;
  6. 新加入到红黑树的节点为红色节点

在上述六点基本的规则之外,我们还可以得到以下几种隐式规则:

  1. 从根节点到叶子节点的最长路径不大于最短路径的2倍:
    怎么样的路径算最短路径?从规则5中,我们知道从根节点到每个叶子节点的黑色节点数量是一样的,那么由纯黑色节点组成的路径就是最短路径。
    那什么样的路径算是最长路径?根据规则4和规则 3,若有红色节点,则必然有一个连接的黑色节点,当红色节点和黑色节点数量相同时,就是最长路径,也就是黑色节点(或红色节点)* 2。
  2. 为什么说新加入到红黑树中的节点为红色节点:
    从规则4中知道,当前红黑树中从根节点到每个叶子节点的黑色节点数量是一样的,此时假如新的是黑色节点的话,必然破坏规则。但如果加入红色节点却不一定,除非其父节点就是红色节点,因此加入红色节点,破坏规则的可能性会小一些。

什么情况下,红黑树的结构会被破坏呢?破坏后又怎么维持平衡,维持平衡主要通过两种方式【变色】和【旋转】,【旋转】又分为【左旋】和【右旋】,两种方式可相互结合。
红黑树节点插入
当我们插入值为66的节点时,红黑树变成了这样:
在这里插入图片描述
很明显,这个时候结构依然遵循着上述 6大规则,无需启动自动平衡机制调整节点平衡状态。此时如果再向里面插入值为51的节点,这个时候红黑树又变成了这样:
在这里插入图片描述
很明显现在的结构不遵循规则4了,这个时候就需要启动自动平衡机制调整节点平衡状态。
【变色】:
我们可以通过变色的方式,使结构满足红黑树的规则:

  1. 首先解决结构不遵循规则4这一点(红色节点相连,节点49 - 51),需将节点49改为黑色;
  2. 此时我们发现又违反了规则5(56 - 49 - 51 - XX 路径中黑色节点超过了其他路径),那么我们将节点45 改为红色节点;
  3. 此时又违反了规则4(红色节点相连,节点 56 - 45 - 43),那么我们将节点56和节点43改为黑色节点;
  4. 但是我们发现此时又违反了规则5(60 - 56 - XX 路径的黑色节点比60 - 68 - XX 的黑色节点多),因此我们需要调整节点68为黑色;
  5. 完成。
    在这里插入图片描述
    最终调整完成后的树为:
    在这里插入图片描述
    但并不是什么时候都那么幸运,可以直接通过变色就达成目的,大多数时候还需要通过旋转来解决,如在下面这棵树的基础上,加入节点65:
    在这里插入图片描述
    插入节点65后进行以下步骤:
    在这里插入图片描述
    这个时候,你会发现对于节点64无论是红色节点还是黑色节点,都会违反规则5,路径中的黑色节点始终无法达成一致,即这个时候仅通过【变色】已经无法达成目的。我们需要通过旋转操作,当然【旋转】操作一般还需要搭配【变色】操作。
    旋转包括【左旋】和【右旋】:
    【左旋】:逆时针旋转两个节点,让一个节点被其右子节点取代,而该节点成为右子节点的左子节点。
    如下图所示,首先断开节点 PL 与右子节点 G 的关系,同时将其右子节点的引用指向节点 C2;然后断开节点 G 与左子节点 C2 的关系,同时将 G 的左子节点的应用指向节点 PL。
    在这里插入图片描述
    【右旋】:顺时针旋转两个节点,让一个节点被其左子节点取代,而该节点成为左子节点的右子节点。
    如下图所示,首先断开节点 G 与左子节点 PL 的关系,同时将其左子节点的引用指向节点 C2;然后断开节点 PL 与右子节点 C2 的关系,同时将 PL 的右子节点的应用指向节点 G。
    在这里插入图片描述

无法通过变色而进行旋转的场景分为以下四种:

  1. 左左节点旋转:这种情况下,父节点和插入的节点都是左节点,以祖父节点【右旋】,搭配【变色】。在这里插入图片描述在这里插入图片描述
  2. 左右节点旋转:这种情况下,父节点是左节点,插入的节点是右节点,先父节点【左旋】,然后祖父节点【右旋】,搭配【变色】。
    在这里插入图片描述
  3. 右左节点旋转:这种情况下,父节点是右节点,插入的节点是左节点,先父节点【右旋】,然后祖父节点【左旋】,搭配【变色】。
    在这里插入图片描述在这里插入图片描述
  4. 右右节点旋转:这种情况下,父节点和插入的节点都是右节点,以祖父节点【左旋】,搭配【变色】。
    在这里插入图片描述
    红黑树插入总结
    在这里插入图片描述
    红黑树节点删除:
    相比较于红黑树的节点插入,删除节点更为复杂,我们从子节点是否为null和红色为思考维度来讨论。
    当子节点至少有一个为null时:删除该节点后,将其有值的节点取代当前节点即可,若都为null,则将当前节点设置为null,当然如果违反规则了,则按需调整,如【变色】以及【旋转】。
    在这里插入图片描述

子节点都是非null节点:情况较为复杂,我们可以采取取巧的方式,我们删除节点的目的是使该节点的值在红黑树上不存在,因此专注于该目的,我们并不关注删除节点时是否真是我们想删除的那个节点,同时我们也不需考虑树结构的变化,因为树的结构本身就会因为自动平衡机制而经常进行调整。

  1. 找到该节点的前驱或者后继:
    前驱:左子树中值最大的节点(可得出其最多只有一个非null子节点,也可能都为null);
    后继:右子树中值最小的节点(可得出其最多只有一个非null子节点,也可能都为 null);
    前驱和后继都是值最接近该节点值的节点,类似于该节点.prev=前驱,该节点.next=后继;
  2. 将前驱或者后继的值复制到该节点中,然后删掉前驱或者后继:
    如果删除的是左节点,则将前驱的值复制到该节点中,然后删除前驱;如果删除的是右节点,则将后继的值复制到该节点中,然后删除后继;

下面以删除前驱为例:

  1. 前驱为黑色节点,并且有一个非null子节点:
    在这里插入图片描述
    因为要删除的是左节点64,找到该节点的前驱63;然后用前驱的值63替换待删除节点的值64,此时两个节点(待删除节点和前驱)的值都为63。删除前驱63,此时成为上图过程的中间环节,但我们发现其不符合红黑树规则4,因此需要进行自动平衡调整。这里直接通过【变色】即可完成。
  2. 前驱为黑色节点,同时子节点都为null:
    在这里插入图片描述
    因为要删除的是左节点64,找到该节点的前驱63;然后用前驱的值63替换待删除节点的值64,此时两个节点(待删除节点和前驱)的值都为63。删除前驱63,此时成为上图过程的中间环节,但我们发现其不符合红黑树规则5,因此需要进行自动平衡调整。这里直接通过【变色】即可完成。
  3. 前驱为红色节点,同时子节点都为null:
    在这里插入图片描述因为要删除的是左节点64,找到该节点的前驱63;然后用前驱的值63替换待删除节点的值64,此时两个节点(待删除节点和前驱)的值都为63;删除前驱63,树的结构并没有打破规则。

红黑树删除总结

  1. 删除的是根节点,则直接将根节点置为null;
  2. 待删除节点的左右子节点都为null,删除时将该节点置为null;
  3. 待删除节点的左右子节点有一个有值,则用有值的节点替换该节点即可;
  4. 待删除节点的左右子节点都不为null,则找前驱或者后继,将前驱或者后继的值复制到该节点中,然后删除前驱或者后继;
  5. 节点删除后可能会造成红黑树的不平衡,这时我们需通过【变色】+【旋转】的方式来调整,使之平衡。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值