目录
红黑树
考纲内容
知识框架
复习提示
1.红黑树的定义
2.红黑树的插入
3.红黑树的删除
归纳总结
红黑树
考纲内容
(一)查找的基本概念
(二)顺序查找法
(三)分块查找法
(四)折半查找法
(五)树形查找
二叉搜索树;平衡二叉树;红黑树
(六)B树及其基本操作、B+树的基本概念
(七)散列(Hash)表
(八)查找算法的分析及应用
知识框架
复习提示
- 本章是考研命题的重点。
- 对于折半查找,应掌握折半查找的过程、构造判定树、分析平均查找长度等。
- 对于二叉排序树、二叉平衡树和红黑树,要了解它们的概念、性质和相关操作等。
- B 树和 B+树是本章的难点。对于B树,考研大纲要求掌握插入、删除和査找的操作过程;
- 对于 B+树,仅要求了解其基本概念和性质。
- 对于散列查找,应掌握散列表的构造、冲突处理方法(各种方法的处理过程)、查找成功和查找失败的平均查找长度、散列查找的特征和性能分析。
1.红黑树的定义
为了保持 AVL 树(平衡二叉树)的平衡性,在插入和删除操作后,会非常频繁地调整全树整体拓扑结构,代价较大。
为此在 AVL树的平衡标准上进一步放宽条件,引入了红黑树的结构。
一棵红黑树是满足如下红黑性质的二叉排序树:
① 每个结点或是红色,或是黑色的。
② 根结点是黑色的。
③ 叶结点(虚构的外部结点、NULL结点)都是黑色的。
④ 不存在两个相邻的红结点(即红结点的父结点和孩子结点均是黑色的)。
⑤ 对每个结点,从该结点到任意一个叶结点的简单路径上,所含黑结点的数量相同。
与折半查找树和 B树类似,为了便于对红黑树的实现和理解,引入了n+1个外部叶结点,以保证红黑树中每个结点(内部结点)的左、右孩子均非空。
图 7.18所示是一棵红黑树。
从某结点出发(不含该结点)到达一个叶结点的任意一个简单路径上的黑结点总数称为该结点的黑高(记为 bh),黑高的概念是由性质⑤确定的。
根结点的黑高称为红黑树的黑高。
结论 1:从根到叶结点的最长路径不大于最短路径的2倍。
由性质⑤,当从根到任意一个叶结点的简单路径最短时,这条路径必然全由黑结点构成。
由性质④,当某条路径最长时,这条路径必然是由黑结点和红结点相间构成的,此时红结点和黑结点的数量相同。
图7.18 中的 6-2和 6-15-18-20 就是这样的两条路径。
结论 2:有n个内部结点的红黑树的高度。
证明:由结论1可知,从根到叶结点(不含叶结点)的任何一条简单路径上都至少有一半是黑结点,因此,根的黑高至少为 h/2,于是有,即可求得结论。
可见,红黑树的“适度平衡”,由 AVL 树的“高度平衡”,降低到“任意一个结点左右子树的高度,相差不超过 2 倍”,也降低了动态操作时调整的频率。
对于一棵动态查找树,若插入和删除操作比较少,查找操作比较多,则采用 AVL树比较合适,否则采用红黑树更合适。
但由于维护这种高度平衡所付出的代价比获得的效益大得多,红黑树的实际应用更广泛,C++中的map 和set(Java中的 TreeMap 和Treeset)就是用红黑树实现的。
2.红黑树的插入
红黑树的插入过程和二叉查找树的插入过程基本类似,不同之处在于,在红黑树中插入新结点后需要进行调整(主要通过重新着色或旋转操作进行),以满足红黑树的性质。
结论 3:新插入红黑树中的结点初始着为红色。
假设新插入的结点初始着为黑色,则这个结点所在的路径比其他路径多出一个黑结点(几乎每次插入都破坏性质⑤),调整起来也比较麻烦。
若插入的结点是红色的,则此时所有路径上的黑结点数量不变,仅在出现连续两个红结点时才需要调整,而且这种调整也比较简单。
设结点z为新插入的结点。插入过程描述如下:
1) 用二叉查找树插入法插入,并将结点z着为红色。
若结点z的父结点是黑色的,无须做任何调整,此时就是一棵标准的红黑树。
2) 若结点z是根结点,则将z着为黑色(树的黑高增 1),结束。
3) 若结点z不是根结点,且z的父结点z.p是红色的,则分为下面三种情况,区别在于z的叔结点y的颜色不同,因z.p是红色的,插入前的树是合法的,根据性质②和④,爷结点
z.p.p必然存在且为黑色。性质④只在z和 z.p之间被破坏了。
情况 1:z的叔结点y是黑色的,且z是一个右孩子。
情况 2:z的叔结点y是黑色的,且z是一个左孩子。
每棵子树T1、T2、T3和T4都有一个黑色根结点,且具有相同的黑高。
情况1(LR,先左旋,再右旋),即z是其爷结点的左孩子的右孩子。
先做一次左旋将此情形转变为情况 2(变为情况2后再做一次右旋),左旋后z和父结点z.p交换位置。
因为z和 z.p都是红色的,所以左旋操作对结点的黑高和性质⑤都无影响。
情况 2(LL,右单旋),即z是其爷结点的左孩子的左孩子。
做一次右旋,并交换z的原父结点和原爷结点的颜色,就可以保持性质⑤,也不会改变树的黑高。
这样,红黑树中也不再有连续两个红结点,结束。
情况1和情况2的调整方式如图7.19所示。
若父结点 z.p是爷结点 z.p.p的右孩子,则还有两种对称的情况:RL(先右旋,再左旋)和RR(左单旋),这里不再赘述。
红黑树的调整方法和 AVL树的调整方法有异曲同工之妙。
情况 3:z的叔结点y是红色的。
情况 3(z是左孩子或右孩子无影响),z的父结点z.p和叔结点y都是红色的,因为爷结点z.p.p是黑色的,将z.p和y都着为黑色,将z.p.p着为红色,以在局部保持性质④和⑤。
然后,把z.p.p作为新结点z来重复循环,指针z在树中上移两层。调整方式如图 7.20所示。
若父结点z.p是爷结点z.p.p的右孩子,也还有两种对称的情况,不再赘述。
只要满足情况3的条件,就会不断循环,每次循环指针z都会上移两层,直到满足 2)(表示z上移到根结点)或情况1或情况2的条件。
可能的疑问:虽然插入的初始位置一定是红黑树的某个叶结点,但因为在情况3中,结点z存在不断上升的可能,所以对于三种情况,结点z都有存在子树的可能。
以图 7.21(a)中的红黑树为例(虚线表示插入后的状态),先后插入5、4和 12 的过程如图 7.21所示。
插入5,为情况 3,将5的父结点3和叔结点 10着为黑色,将5的爷结点变为红色,此时因为7已是根,所以又重新着为黑色,树的黑高加1,结束。
插入4,为情况1的对称情况(RL),此时特别注意虚构黑色空结点的存在,先对5做右旋;转变为情况2的对称情况(RR),交换3和4的颜色,再对3做左旋,结束。
插入12,父结点是黑色的,无须任何调整,结束。
3.红黑树的删除
红黑树的插入操作容易导致连续的两个红结点,破坏性质④。
而删除操作容易造成子树黑高的变化(删除黑结点会导致根结点到叶结点间的黑结点数量减少),破坏性质。
删除过程也是先执行二叉查找树的删除方法。
若待删结点有两个孩子,不能直接删除,而要找到该结点的中序后继(或前驱)填补,即右子树中最小的结点,然后转换为删除该后继结点。
由于后继结点至多只有一个孩子,这样就转换为待删结点是终端结点或仅有一个孩子的情况。
最终,删除一个结点有以下两种情况:
- 待删结点只有右子树或左子树。
- 待删结点没有孩子。
1) 若待删结点只有右子树或左子树,则只有两种情况,如图7.22 所示。
只有这两种情况存在。子树只有一个结点,且必然是红色,否则会破坏性质。
2) 待删结点无孩子,且该结点是红色的,这时可直接删除,而不需要做任何调整。
3) 待删结点无孩子,且该结点是黑色的,这时设待删结点为y,x是用来替换y的结点(注意,当y是终端结点时,x是黑色的 NULL结点)。
删除y后将导致先前包含y的任何路径上的黑结点数量减1,因此y的任何祖先都不再满足性质⑤,简单的修正办法就是将替换y的结点x视为还有额外一重黑色,定义为双黑结点。也就是说,若将任何包含结点x的路径上的黑结点数量加1,则在此假设下,性质⑤得到满足,但破坏了性质①。
于是,删除操作的任务就转化为将双黑结点恢复为普通结点。
分为以下四种情况,区别在于x的兄弟结点w及w的孩子结点的颜色不同。
情况 1:x的兄弟结点 w是红色的。
情况 1,w必须有黑色左右孩子和父结点。交换 w和父结点 x.p的颜色,然后对 x.p 做一次左旋,而不会破坏红黑树的任何规则。
现在,x的新兄弟结点是旋转之前w的某个孩子结点,其颜色为黑色,这样,就将情况1转换为情况 2、3 或4处理。
调整方式如图 7.23 所示。
情况 2:x的兄弟结点w是黑色的,且w的右孩子是红色的。
情况 3:x的兄弟结点w是黑色的,w的左孩子是红色的,w的右孩子是黑色的。
情况 2(RR,左单旋),即这个红结点是其爷结点的右孩子的右孩子。
交换w和父结点x.p的颜色,把w的右孩子着为黑色,并对x的父结点x.p做一次左旋,将x变为单重黑色,此时不再破坏红黑树的任何性质,结束。
调整方式如图 7.24所示。
情况3(RL,先右旋,再左旋),即这个红结点是其爷结点的右孩子的左孩子。
交换w和其左孩子的颜色,然后对w做一次右旋,而不破坏红黑树的任何性质。
现在,x的新兄弟结点w的右孩子是红色的,这样就将情况3转换为了情况 2。
调整方式如图7.25 所示。
情况 4:x的兄弟结点w是黑色的,且w的两个孩子结点都是黑色的。
在情况 4 中,因为w也是黑色的,所以可从x和 w上去掉一重黑色,使得x 只有一重黑色而 w变为红色。
为了补偿从x和w中去掉的一重黑色,把x的父结点x.p额外着一层黑色,以保持局部的黑高不变。
通过将 x.p 作为新结点x来循环,x 上升一层。
若是通过情况1进入情况 4的,因为原来的x.p是红色的,将新结点x变为黑色,终止循环,结束。
调整方式如图 7.26 所示。
若x是父结点 x.p的右孩子,则还有四种对称的情况,处理方式类似,不再赘述。
归纳总结
在情况4中,因x的兄弟结点w及左右孩子都是黑色,可以从x和w中各提取一重黑色(以让 x 变为普通黑结点),不会破坏性质④,并把调整任务向上“推”给它们的父结点 x.p。
在情况1、2和3中,因为x的兄弟结点 w或w左右孩子中有红结点,所以只能在x.p子树内用调整和重新着色的方式,且不能改变 x 原根结点的颜色(否则向上可能破坏性质④)。
情况1虽然可能会转换为情况 4,但因为新x的父结点 x.p是红色的,所以执行一次情况4 就会结束。
情况 1、2和3在各执行常数次的颜色改变和至多3次旋转后便终止,情况 4是可能重复执行的唯一情况,每执行一次指针x上升一层,至多 次。
以图 7.27(a)中的红黑树为例(虚线表示删除前的状态),依次删除5 和 15 的过程如图 7.27所示。
删除 5,用虚构的黑色 NULL 结点替换,视为双黑 NULL结点,为情况 1,交换兄弟结点12 和父结点8的颜色,对8做一次左旋;
转变为情况 4,从双黑 NULL 结点和 10 中各提取一重黑色(提取后,双黑 NULL 结点变为普通 NULL 结点,图中省略,10 变为红色),因原父结点 8是红色,所以将8变为黑色,结束。
删除15,为情况3的对称情况(LR),交换8和 10 的颜色,对8做左旋;
转变为情况2的对称情况(LL),交换10和12的颜色(两者颜色一样,无变化),将 10 的左孩子 8着为黑色,对12 做右旋,结束。