红黑树相关知识点详解

文章目录

修改自:《Java高级程序员面试笔试宝典》(机械工业出版社)第5.3.3节

1. 二叉查找树

对于有序数列的查找,

  • 遍历方式时间复杂度为O(n);
  • 二分查找法时间复杂度为O(log2n);

二叉查找树即是以二分法思想设计的一种快速查找树,具有如下特性:

  • 每一个结点关键字只会在树中出现一次。
  • 任何一个节点如果有子结点,那么左侧的关键字一定比较小,右侧的关键字一定比较大。

2. 平衡二叉树(AVL树)

2.1 定义

二叉查找树在进行多次插入和删除后,往往会朝着链表的方向退化,导致查找效率越来越低下。如图是极端情况下退化成链表的二叉查找树:

在这里插入图片描述
[图1 极端情况下的二叉查找树]

为了提高二叉树的查询效率,提出了平衡二叉树(AVL树)的概念,包括如下特点:

  • 平衡二叉树是一棵空树或二叉查找树;

  • 左右两个子树的高度差绝对值不超过1;

  • 左右两个子树都是一棵平衡二叉树。

满足这些条件,查询时间复杂度不超过O(log_2n)。

在对平衡二叉树做插入或删除的时候,需要判断该树是否失衡,通过一系列旋转操作(自平衡),来让其始终满足平衡二叉树的条件,从而达到查找效率最优。

决定平该树是否失衡的关键变量为平衡因子bf,则:

​ bf§ = p左子树高度 - p右子树高度,

有如下特性:

  • 结点平衡因子变化后,回溯修改父结点的平衡因子;
  • 当平衡因子等于-2或2的时候,认为以该结点为根结点的树失衡;
  • 失衡后需要进行修复,修复完成后,停止回溯修改父结点的平衡因子。

下面以如下平衡二叉树为例,介绍不同操作后如何维持平衡二叉树的特性。
在这里插入图片描述
[图2 样例 - 平衡二叉树]

2.2 插入操作

插入操作有四种失衡情况:

2.2.1 结点平衡因子为2,左孩子平衡因子为1,进行LL旋转(单向右旋)。

比如插入7,由于比10小,放在了10的左侧,此时受影响而失衡的最小子树如图:
在这里插入图片描述
[图3 插入结点7后的二叉树]

其左子树为根节点10,左侧插入了7,对于这种情况,可以以13为旋转点进行单向右旋,旋转后子树代替原树的13结点,重新构成了平衡二叉树,如图:
在这里插入图片描述
[图4 插入结点7右旋后的结果]

2.2.2 结点平衡因子为-2,右孩子平衡因子为1,则进行RR旋转(单向左旋)。

旋转方式和 2.2.1 的情况正好相反,参考 2.2.1 图解。

2.2.3 结点平衡因子为2, 左孩子平衡因子为-1,进行LR旋转(先左再右)。

比如插入结点19后,找到失衡的最小子树如图:
请添加图片描述

[图5 插入结点19后的二叉树]

对该最小子树的左子树进行左旋,然后再对整棵树进行右旋,使子树重新恢复平衡:
请添加图片描述
[图6 插入19后先左再右旋转的结果]

2.2.4 结点平衡因子为-2,左孩子平衡因子为1,进行RL旋转(先右再左旋转)。

旋转方式与 2.2.3 的情况相反,参考 2.2.3 的图例。

2.3 删除操作

2.3.1 如果删除的结点的左右子结点任意一个为空,那么用另一个非空子结点直接替换当前结点,并回溯校验父结点的平衡因子。

如果没有子结点,其实也满足该条件,即用空结点来替换当前结点。
请添加图片描述
[图7 删除结点31的情况]

如上图的情况,删除后符合LL单向右旋的情况。

2.3.2 如果删除的结点的左右子结点都不为空,则分两种情况:

2.3.2.1 当平衡因子为 0 或 1 时,在左子树里找到最大值,交换待删除结点与该最大值结点的值,然后删除该最大值结点。

如下例子删除结点76,首先交换76与72,然后删除原来72对应的结点。

可以看到最小失衡树根结点为31,平衡因子为2,其左子树10平衡因子为0,不满足之前LL旋转,也不满足LR旋转,和上一步一样,平衡因子0当作1一样的处理,进行LL单向右旋。

请添加图片描述
[图8 删除结点76]

2.3.2.2 当平衡因子为-1时,则是在右子树里查找最小值,用这个最小值与待删除的结点进行交换,然后删除交换前最小值对应的结点,其余操作与上述操作相反。

3. 红黑树(R-B树)

3.1 性质:

红黑树也是一种自平衡二叉树,性能由于平衡二叉树,有如下五个性质:

  1. 结点是红色或者黑色;
  2. 根节点是黑色;
  3. 每个叶子结点(指NIL结点,实际不存在的结点)为黑色;
  4. 每个红色结点的两个子结点都是黑色;
  5. 从任一结点到其每个叶子节点的所有路径都包含相同数目的黑色结点(这里的黑色结点不包括性质3中的NIL结点)。

3.2 推论:从根到叶子的最长路径,不超过最短路径的两倍

推导过程:

性质5约束了黑色结点数目一定相等,性质4约束了不会有两个相邻的红色结点。所以可能的最长路径也就是以黑色结点结束的红黑相间的结点,红色结点数目最多为黑色结点数目-1,红色+黑色不可能超出黑色*2。

对红黑树进行增删操作,必定会违背这些性质,故也需要在插入删除时做一些特定的操作。

红黑树结点,除了和其他二叉树一样的 left / right / parent 结点引用之外,还有颜色(red/black)属性,以及是否为叶子结点(isNil)标记。

3.3 插入操作

因为性质5的约束,所有新插入的结点都是红色结点

假设插入结点为N,父结点为P,祖父结点为G,叔结点为U,定义一个函数 f(A, B),函数返回A结点相对于B结点的位置(left/right)。

插入流程:

3.3.1 如果该树为空树,那么N跟根结点,变色为黑(性质2)。

3.3.2 如果P为黑色,那么由于新增的结点为红色,不会违背性质5,满足红黑树性质,所以不做任何操作。

3.3.3 如果P为红色,那么分多种子情况处理:

3.3.3.1 U为红色,把P、U改为黑色、G改为红色。G改为红色后,由于G的父结点也可能是红色,从而违背性质4,这时,把G结点视为新插入的结点,递归进行插入操作。

(下图中空心结点表示红色结点,实心结点表示黑色结点)

请添加图片描述
[图9 U为红色的情况]

3.3.3.2 U为黑色,且 f(P,G) = f(N,P),则将P、G变色,对G为根节点的树左单向旋转(f(P,G)=L则LL右旋转,为R则RR左旋转),旋转是为了保证子树上的黑色结点总数一致。

如下例,P在G左侧,N在P左侧,变色后作LL单向右旋转。
请添加图片描述
[图10 LL单向向右旋转]

3.3.3.3 U为黑色,且f(P,G)!=f(N,P),对P进行一次单向旋转,转化为f(P,G)=f(P,N)情况。

如下例,P在G左侧,N在P右侧,以P为旋转点进行RR单向左旋。
请添加图片描述
[图11 RR单向左旋]

3.4 插入过程总结

红黑树插入过程的主要操作有两种:

变色:用于调整两个红色结点相邻的情况,以适应性质4。

旋转:用于调整左右子树黑色结点数目不等的情况,以适应性质5。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值