7.8.红黑树的定义和性质(红黑树英文缩写为RBT)

一.为什么要发明红黑树:

二叉排序树(BST)、平衡二叉树(AVL Tree)、红黑树(Red-Black Tree,缩写为RBT)是一个家族,都是用于查找的二叉树,

BST诞生于1960年,AVL Tree诞生于1962年、Red-Black Tree诞生于1972年,

通过上述图片可知Red-Black Tree在查找、插入、删除操作的效率等同于AVL Tree,既然Red-Black Tree和AVL Tree的效率等同,为什么要发明红黑树呢?

在平衡二叉树中每插入/删除一个结点后,很有可能会破坏平衡二叉树的平衡性,由于平衡二叉树要求任何一个结点的左子树与右子树的高度只差不超过1,因此这种特性很容易被插入/删除一个结点给破坏,而一旦破坏了平衡性,就需要频繁地调整树的形态使其恢复平衡,比如在插入一个新结点之后,导致不平衡,首先要计算平衡因子,找到最小不平衡子树,这两步的时间开销就比较大,确定了最小不平衡子树之后再进行调整(包含四种情况:LL、RR、LR、RL),因此插入/删除一个结点带来的时间开销就比较大;

相比之下,红黑树在插入/删除一个结点后,大多不会破坏红黑树的特性,因此就不需要频繁地调整树的形态,同时在插入/删除一个结点之后,也不需要计算平衡因子和找最小不平衡子树,所以在红黑树中插入/删除一个结点所带来的时间开销要比平衡二叉树低得多,即使插入/删除结点破坏了红黑树的特性,需要对这棵树的形态进行调整,也可以在常数级的时间开销内完成调整,

所以红黑树相比于平衡二叉树来说插入/删除操作实现起来要更高效,这就是发明红黑树的原因。

平衡二叉树适用于以查找结点为主、很少插入/删除结点的场景;红黑树适用于频繁地插入/删除结点的场景,实用性更强。


二.红黑树大概会怎么考?

有关红黑树,重点掌握红黑树的定义、性质、查找、插入、修改操作,删除操作了解即可。


三.红黑树的定义:

1.定义:

如上述图片,

  • 红黑树相比于二叉排序树:红黑树是二叉排序树的一种优化,因此红黑树必定是二叉排序树,二叉排序树具有"左子树中每一个结点的值<根结点的值<右子树中每一个结点的值"的特性,因此红黑树也有该特性。此外,为了保证查找、插入、删除操作的效率,红黑树还具有上述图片描述的特性

  • 红黑树相比于平衡二叉树:平衡二叉树必须满足任何一个结点的左、右子树的高度之差不超过1,红黑树就没有这个特性。平衡二叉树中每一个结点除了保存关键字、左孩子指针、右孩子指针外还需要记录平衡因子,而红黑树需要给每个结点标注颜色(红色/黑色),而不是平衡因子

  • 红黑树特有的特征:红黑树的结点增加了父结点指针,可以高效地实现从下往上找某个结点的父结点;红黑树的每一个结点都必须标注是红色还是黑色;红黑树的根结点一定是黑色的;红黑树的叶子结点一定是黑色的->在红黑树里提到叶子结点时,该叶子结点通常指的是失败结点即查找失败的结点,又叫NULL结点或者外部结点;在红黑树里提到叶子结点时指的并不是最下面一层包含关键字的结点,而是查找失败的NULL结点,红黑树里所有叶子结点都视为黑色

  • 红黑树中外部结点是叶子结点,为NULL;内部结点是具有关键字的结点,不为NULL

  • 红黑树里的叶子结点对应的是一个空指针,因此在内存中不会给叶子结点malloc一片空间。叶子结点只是最下层的一个空指针,只不过在处理红黑树时会把这个叶子结点(空指针)对应一个黑结点,因为会发现当处理红黑树时,要找一个结点的叔叔结点,会出现叔叔结点就是叶子结点,所以把叶子结点视为黑色是有意义的

2.红黑树特征口诀:

Ⅰ."左根右":指的是红黑树中任何一个结点都有"左子树中每一个结点的值<根结点的值<右子树中每一个结点的值";

Ⅱ."根叶黑":红黑树的根结点、叶子结点都必须是黑色的;

Ⅲ."不红红":红黑树中不存在两个相邻的红色结点;

Ⅳ."黑路同":红黑树中从任何一个结点出发,一路走到最下面的任一叶子结点,这条路上所经过的黑结点的数量一定是相同的。

3.定义红黑树结点的代码:

#include<stdio.h>
​
struct RBnode //红黑树的结点定义
{
    int key; //关键字的值
    RBnode* parent; //父结点指针
    RBnode* lChild; //左孩子指针
    RBnode* rChild; //右孩子指针
    int color; //结点颜色,如:可用 0/1 表示 黑/红,也可使用枚举型enum表示颜色,布尔类型也可以 
}; 
​
int main()
{
    return 0;
}

4.实例:

以上述图片的红黑树为例,

  1. 红黑树中每个结点或是红色、或是黑色的:上述图片的红黑树中任意一个结点要么是红色,要么是黑色

  2. 红黑树的根结点必须是黑色的:上述图片的红黑树的根结点为13结点,必须是黑色的

  3. 红黑树的叶子结点(外部结点、NULL结点、失败结点)均是黑色的:上述图片的红黑树里的叶子结点(外部结点、NULL结点)都为NULL->当查找失败时指针会落在NULL上,所以红黑树的叶子结点也叫失败结点。在红黑树里提到叶子结点时指的并不是最下面一层包含关键字的结点,而是查找失败的NULL结点,红黑树里所有叶子结点都视为黑色

  4. 红黑树中不存在两个相邻的红结点(即红结点的父结点和左、右孩子结点均是黑色的):上述图片的红黑树里的17结点是红色的,那么它的父结点和左、右孩子结点就都必须是黑色的,但凡有一个是红色的,就意味着在这个红黑色的查找路径上出现了连续的两个红色结点,这就不符合红黑色的特性;22结点和27结点不算连续的红色结点,因为他们两个不连在一起,像这种兄弟关系的结点出现两个红结点是没关系的,但父子关系如果连续出现了红结点,就不满足红黑树的要求

  5. 对红黑树里的任何一个结点,从该结点到任一叶子结点的简单路径上,所含黑结点的数目相同:比如从上述图片的红黑树里的根结点13出发,要到达它下面某一个叶子结点,其中有很多条路,比如:13->8->1->NULL,13->8->1->6->NULL,13->8->11->NULL,13->17->15->NULL,每一条路径中都经过了3个黑结点;再比如从17结点出发,到达它下面的任何一个NULL结点,比如17->15->NULL,经过了2个黑结点,17->25->22->NULL,也经过了2个黑结点


四.练习:是否符合红黑树要求?

1.例一:

上述图片左边的树显然不是红黑树,

因为它不满足"不红红"即出现了两个相邻的红结点。

上述图片右边的树显然不是红黑树,

因为它不满足"根叶黑"即根结点不是黑色的。

2.例二:

上述图片的树不是红黑树,

因为它不满足"黑路同"即出现了从任意结点出发达到任一叶子结点的路径中,出现的黑色结点的数量不同,比如从1结点出发,1->NULL出现了2个黑色结点,1->6->NULL出现了3个黑色结点,

但如果把6结点改为红色,就能满足"黑路同",比如从1结点出发,1->NULL出现了2个黑色结点,1->6->NULL出现了2个黑色结点,

如下图:

如上图,

但此时依旧不是红黑树,为什么呢?问题出在7号结点,红黑树也是二叉排序树,所以必须有"左<根<右",此时8号结点的右子树为7号结点,即"根>右",所以违反了"左根右"

如果把7结点改为11结点,此时满足了"左<根<右",

最终就是一棵正确的红黑树,

如下图:


五.补充概念:结点的"黑高"

1.概念:

如上图,

在红黑树中,每一个结点都有一个属性"黑高",

"黑高"就是从某个结点出发(不含该结点)到达该结点下面的任一空叶子结点的路径上黑结点总数,

比如15结点的"黑高"为2,因为从15结点出发,到达15结点(不包含15结点)下面任何一个空叶子结点所经过的黑结点的总数为2,比如15->11->8->NULL,

由于红黑树具有"黑路同"的特性,所以从15结点出发,到达15结点(不包含15结点)下面的任何一个叶子结点所经过的黑色结点数量都是相同的,所以15结点的"黑高"随便找一条路即可得到。

根结点6的"黑高"为2,从根结点6出发,不包含根结点6本身,到达根结点6下面的某一个叶子结点,比如走6->2->NULL,总共经过了2个黑色结点,因此根结点6的"黑高"为2,走"6->15->11->8->NULL"也是总共经过了2个黑色结点,

结点"黑高"的属性可用于证明红黑树的某些特性,之后会详细说明。

2.思考:根结点的黑高为h的红黑树,内部结点数(即包含关键字的结点)至少有多少个?

空结点即叶子结点称为外部结点。

如上图,

先说结论->

若一棵红黑树的根结点黑高为h,那么内部结点数(即包含关键字的结点)至少有个。

证明->                

现在是已知黑高h的情况下即有黑色结点,要求内部结点数最少,那么就不能有红色结点,因为红色结点必定包含关键字,在黑高相等的情况下有红色结点的红黑树中内部结点数会更多,所以不能有红色结点,

因此黑高h就代表这一条路上全是黑色结点,而且是h个黑色结点,这h个结点中包含1个叶子结点,所以黑高h中只有h-1个内部结点,但根结点也是内部结点,

"左根右"、"根叶黑"、"不红红"的特性可以保证,因为红黑树基于二叉排序树,且根结点、叶子结点必定是黑色的,此时红黑树中没有红色结点,

唯独"黑路同"的特性要注意,这时的红黑树中只有黑色结点,而且红黑树也是二叉树即仅包含左孩子和右孩子,因此如果一边的黑高为h,那么另一边的黑高也必须是h,因为如果另一边的黑高不是h,那么就违反了黑路同的特性,

所以可得出当前红黑树必须是满二叉树的状态下,才能保证内部结点数最少。

比如上述图片中间的红黑树,

该红黑树的根结点黑高bh为2,内部结点最少的情况只可能是所有的结点都是黑色且满树的状态,

如果不满的话比如根结点的右子树直接接了叶子结点(此时左子树的黑高为2,右子树的黑高为1),那么就违反了"黑路同"的特性。

由于是满树,且红黑树也是二叉树,同时黑高h也反映了该满树的高度,

第一层有1个结点即2⁰个结点;

第二层有2个结点即2¹个结点;

第三层有4个结点即2²个结点;

以此类推,

第h层有个结点,

所以这h层总共有2⁰+2¹+2²+...+=〔2⁰ ∗(1-)〕/(1-2)=个内部结点(这里用到了等比数列求和,满二叉树的结点总数详情见"5.3.二叉树的定义和基本术语"),

因此高度为h的满二叉树总共有个结点。

因此一棵红黑树的根结点黑高为h,那么内部结点数(即包含关键字的结点)至少有个。


六.红黑树的性质:

性质1:从根结点到叶子结点的最长路径不大于最短路径的2倍。

该性质可以通过上述图片里的特性4、5推出,

假设红黑树中有n个黑色结点,

由于从根结点(黑色)出发到达任一叶子结点(黑色)所经过的黑色结点的数量是相同的,

但是在这条路上又要求"不红红",也就是根结点到叶子结点的这条路上不可能出现两个连续的红色结点,这些红色的结点只有可能穿插在各个黑色结点中间,

所以最长路径为红+黑,其中红不相邻,因此红不大于黑,所以红+黑不大于2黑即红+黑不大于2n(从根结点到叶子结点中经历了其他红色的结点),

最短路径为黑+黑即小于等于n(可能直接根结点到叶子结点),

因此就得出最长路径不大于最短路径的2倍。

性质2:有n个内部结点的红黑树高度h≤2log₂(n+1)。

性质2证明:

若红黑树总共有n个内部结点,总高度为h,

那么根结点的黑高一定大于等于h/2,因为"不红红"的特性(根结点的黑高最大为总高度h即一路全是黑结点;最小为黑、红穿插,要让黑高最小,必须尽可能地插入红结点,红结点最多在两个黑结点中插一个,由于"根叶黑"的特性,如果黑结点下面就是叶子结点,那么黑高大于h/2,如果红结点下面就是叶子结点,那么黑高等于h/2,可以画图验证),

又因为"如果一棵红黑树的根结点黑高为h/2,那么内部结点数(即包含关键字的结点)至少有个",所以内部结点数n≥,由此推出h≤2log₂(n+1)。

由性质2可知如果红黑树有n个内部结点,那么红黑树查找操作的时间复杂度为O(log₂n),

红黑树高度h为数量级O(log₂n),红黑树高度h不超过数量级O(log₂n),也就可以保证红黑树查找、插入、删除操作的时间复杂度不超过O(log₂n)->查找效率与AVL树同等数量级。

性质3:在红黑树当中,任何一个结点的左子树和右子树的高度之差不超过2倍。

性质3可由性质1推出。

这时就可以发现红黑树(RBT)和平衡二叉树(AVL)的一些联系,

平衡二叉树中要求任何一个结点的左子树和右子树的高度之差不超过1,这个限制很严格;

红黑树中要求任何一个结点的左子树和右子树的高度之差不超过2倍,这个限制没那么严格,

正是因为红黑树的要求没那么严格,而平衡二叉树的要求更加严格,

导致在插入、删除操作中红黑树的特性不太容易被破坏,而平衡二叉树的平衡性很容易被破坏,

由于每一次的破坏都需要进行调整,所以红黑树要调整的次数通常比平衡二叉树少,因此红黑树比平衡二叉树的效率要高,

这也就是为什么在插入、删除操作中红黑树比平衡二叉树更高效。


七.红黑树的基本操作:

1.红黑树的查找:

红黑树是二叉排序树即二叉查找树,因此红黑树的查找和二叉排序树是一样的,

查找目标关键字首先需要从根结点出发,如果要查找的目标关键字小于根结点的关键字就往左走,大于根结点的关键字就往右走,以此类推,直到找到目标关键字为止,意味着查找成功;

或者到达空结点NULL为止,意味着查找失败。

2.红黑树的插入:

详情见"7.9.红黑树的插入"。

3.红黑树的删除:

详情见"7.10.红黑树的删除"。

4.红黑树的修改:

只需要实现红黑树的查找后进行修改即可。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值