红黑树

红黑树性质

1.每个结点或是红的,或是黑的
2.根结点是黑的
3.每个叶结点(NIL)是黑的
4.如果一个结点是红的,则它的两个儿子都是黑的
5.对每个结点,从该结点到叶结点的所有路径上包含相同数目的黑结点
从某个结点x出发(不包括该结点)到达一个叶结点的任意一条路径上,黑结点的个数成为该结点x的黑高度,用bh(x)表示。

红黑树的插入

我们为了简化RB-INSERT-FIXUP的过程,让新插入的结点Z的着为红色(如果插入结点Z为黑色,则第5条性质不能满足)。当Z为红色时,第4条性质可能不能满足,因此我们必须调整树形,也就是旋转树形并改变结点颜色。
为了方便讨论,让我先为某些特殊结点定义一些代名。假设新结点为Z,其父结点为P,祖父结点为G,伯父结点为Y,曾祖父结点为GG。
根据红黑树的第四条性质,Z必为红,若P为红,则G必为黑。

Z是P的左孩子
case 1: 变化前

case 1: 变化后
这里写图片描述
Z是P是右孩子
case 1: 变化前
这里写图片描述
case 1: 变化后
这里写图片描述
只有在P和Y都是红色的时候才会执行case 1. 既然变化前G是黑的,我们可以将P和Y都着为黑色以解决Z和P都是红色的问题, 此时既满足了性质4、也没有破环性质5。然后把G当作新增的结点Z来重复while循环,即父子结点皆为红色的情况持续向RB-tree的上层结构发展。本文最后给出一种改进的办法,从而解决处理时效上的瓶颈。

Z是P的左孩子
case 2:变化前
这里写图片描述

case 2:变化后
这里写图片描述

case 3:变化前
这里写图片描述
case 3:变化后
这里写图片描述

case 3通过对结点P进行左旋, 转化成case 2。再case 2 中通过对结点G进行右旋,并改变某些结点的颜色。这样,由于在一行中不再有两个连续的红色结点,因而,所有的处理到此完毕。

改进:
为了避免case 1 中“父子结点皆为红色”的情况持续向RB-Tree的上层结构发展,形成处理时效上的瓶颈,我们可以施行一个由上而下的程序:假设新增结点为A,那么就延着A的路径,只要看到某结点X的两个子节点皆为红色,就把X改成红色,并把两个子节点改成黑色。
这里写图片描述
但是如果A的父结点P为红色,我们可以做一次
case 2和 case 3 的变化,。在此之后,结点35的插入就很单纯了:要么直接插入,要么插入后再一次单旋转即可。
这里写图片描述

红黑树的删除

当删除的结点Y是红色的话,红黑树性质仍然得以保持:

  • 树中各结点的黑高度都没有变化
  • 不存在两个相邻的红色结点
  • 因为如果Y是红的,就不可能是根,所以跟仍然是黑色的

传递给RB-DELETE-FIXUP的结点X是两个结点中一个:在Y被删除之前,如果Y有一个不是哨兵nil[T]的孩子,则X为Y的唯一孩子;如果Y没有孩子,则X为哨兵nil[T]。

当删除的结点Y是黑色的话,会产生三个问题:

  • 如果Y原来是根结点,而Y的一个红色的孩子成为了新的根,违反了性质2
  • 如果X和P[Y](现在也是P[X])都是红的,违反了性质4
  • 删除Y将导致先前包含Y的任何路径上黑结点个数少1
    当性质5倍破环后,我们可以把结点X视为还有额外的一重黑色,也就是说,如果将任意包含结点X的路径上黑结点个数加1,则性质5成立。当将黑结点Y删除时,将其黑色“下推”至其子结点,这样结点X是双重黑色或红黑,这就分别给包含X的路径上黑结点个数贡献2个或1个,但是X的color属性仍然是RED(如果X是红黑的)或BLACK(如果x是双重黑色)

解决方案:将额外的黑色沿树上移,直到:

  • X指向一个红黑结点,将X单独着为黑色
  • X指向根,这时可以简单地消除那个额外的黑色,或者
  • 做必要的旋转和颜色修改
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值