红黑树结点的插入与删除

在开始说红黑树结点的插入和删除之前,先介绍几个概念。

红黑树的性质:

1、每个结点或是红色,或是黑色的。

2、根结点是黑色的。

3、每个叶子结点是黑色的。

4、如果一个结点是红色的,则它的两个子结点都是黑色的。

5、对每个结点, 从该结点(不含该结点)到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点。

额外性质:由于红黑树是一棵二叉搜索树,所以二叉搜索树的性质,红黑树也是具备的。(二叉搜索树这里就不多说了)

注意,我们定义一个黑色的nil结点,当这个红黑树是空树的时候,root指向这个nil结点。当这棵树不是空树的时候,根结点的父结点指向这个nil结点,新插入的结点的左右孩子结点也都指向这个nil结点,所以这个nil结点也就是叶子结点了。我们下面的图都是忽略了叶子结点的显示。

黑高:从某个结点x出发(不含该结点)到达一个叶子结点任意一条简单路径上的黑色结点个数称为该结点的黑高。

二叉搜索树的左旋和右旋:

从上图可以直到无论是对x结点的左旋或者对y结点的右旋,在旋转前和旋转后,二叉树搜索树的性质都是满足的。通过这个 操作,红黑树也是可以一直保持二叉树的性质。

红黑树结点的插入:

红黑树插入新的红色结点,这是因为插入红色不会改变插入点所在分支的路径上的黑色结点的数量,因此之后的调整就不用考虑因为黑色结点的数量改变而导致红黑树性质破坏的情况了,这个时候只需要判断增加的结点后性质2和性质4是否有破坏就可以了。

当我们插入一个新的红色结点后,就开始调整操作(调整操作不会影响根结点的黑高,只会调整结点的颜色),调整操作完成后把root的颜色改成黑色(蕴含调整操作后造成性质2被破坏,后文会有这种情况出现的说明)。

插入结点的调整操作的迭代:

 下图是引用的是《算法导论》中的插图

调整操作会进行多次,每次迭代有6种情况要分析,但是因为其中3种与另外3种是左右对称的,区分条件是z结点的父结点是z结点的祖父结点的左孩子还是右孩子,所以我们只需要讨论其中3种就可以了。我们讨论的是z结点的父结点是z结点的祖父结点的左孩子这种情况。

图中的z结点代表每一次调整迭代前后一个可能破坏红黑树性质的结点,但是这个结点的子树是满足红黑树性质的,y结点是z结点的叔结点。每一次的迭代的目标就是使得z结点的子树都满足红黑树的性质。迭代前先判断z结点的父结点是否红色,如果是红色那么就破坏了性质4,所以开始迭代,否则完成调整操作了。这个时候,当z结点是root的时候由于z结点是红色的(破坏了性质2),所以调整操作后,我们需要把 root的颜色改为黑色。

迭代的情况1(上图中情况1的转换):如果y结点是红色的,那么把y结点和z结点的父结点改为黑色把z结点的祖父结点改为红色,然后把z指向z结点的祖父结点,然后y指向当前z结点的叔结点。这个时候z结点的子树都满足红黑树的性质,可以进行下一次的迭代了。

迭代情况2(上图中的情况2的转换):如果y结点是黑色的,而且z结点是z结点的父结点的右子结点,那么对z结点的父结点做一个左旋操作,这样子我们就可以转化成迭代情况3。这个时候无需进行下一次的迭代,只要在当前迭代中做情况3的转换。

迭代情况3(上图中的情况3的转换):如果y结点是黑色的,而且z结点是z结点的父结点的左子结点,那么把z结点的父结点改为黑色,把z结点的祖父结点改为红色,然后对z结点的祖父结点做一个右旋操作。这个时候由于z结点的父结点是黑色的,所以调整操作结束。

上述的3种情况的调整都不会在增加或者减少整棵树的所有路径种的黑色结点数量,所以不会出现破坏性质5的情况。这就是为什么要加入的是红色结点而不是黑色结点,加入黑色结点会破坏性质5,要通过调整来维护性质5比维护性质4要容易很多。

移植操作:

移植操作有三个参数,指向根结点的root指针,指向要被移除的子树u的指针与指向要被移植的子树v的指针。如果u的父结点是nil结点,那么把root指向v,同时把v的夫系欸但你指针指向nil结点。当u的父结点不是nil结点的时候,如果u是u的父结点的左(右)孩子结点,把u的父结点的左(右)孩子指针指向v,同时把v的父结点指针指向u的父结点。

红黑树结点的删除:

定义y指针指向要删除的结点,x指针指向要移植到y位置的以y的孩子结点为根结点的子树的根结点。

当删除结点的时候有三种情况:

情况1:当删除的结点z的左孩子结点是nil结点的时候,把y指向z,把x指向y的右孩子结点。然后,把y作为u,把x作为v,运行移植操作。

情况2:当删除的结点z的右孩子结点是nil结点的时候,把y指向z,把x指向y的左孩子结点。然后,把z作为u,把x作为v,运行移植操作。

注意:前面的两个操作都蕴含这当删除的结点的左右孩子结点都是nil结点的情况,所以不做讨论。

情况3:当删除的结点z左右孩子都不是nil节点的时候,寻找要z的中序遍历的后继结点(也就是右子树的最小的结点)y,把x指向y的右孩子结点。然后,把y作为u,x作为v(y的左孩子结点必定是nil结点),运行移植操作。然后把y替换掉要z,同时把y的颜色改成z的颜色。

从以上可以看出情况3的处理是,先通过找到后继结点y来转换成情况1来做情况1的处理(情况3的x与y和情况1的x与y对应)。

通过上面的3种情况处理删除结点后,要判断y的颜色,当y的颜色是红色,那么对于这棵红黑树来说少了一个红色结点是不会破坏红黑树的性质,所以删除操作完成。当y的颜色是黑色的时候,那么对于这棵红黑树来说,因为原来x的这个位置上存在着一个黑色结点y,黑色结点少了1个,所以经过x结点的路径上的黑高会减少1,那么x就是那个破坏了红黑树性质的结点了。幸好的是x的左右子树都满足红黑树的性质。

删除结点的调整操作的迭代:

经过上面的分析可以知道,如果结点y是黑色的,那么性质5必定会被破坏,这个时候我们以结点x作为调整点调整。当结点x是红色的时候,只需要要把x改成黑色就可以了,因为性质5被破坏是因为y的黑色被去掉了黑高少1,所以把x改成黑色就可以补回来。当结点x是黑色的时候需要迭代来完成调整。每一次迭代的目标就是使得结点x到其所有后代叶子结点的黑高相等。每一次迭代前,当结点x为红色或者结点x是根结点的时候就可以停止迭代了。因为当结点x为红色的时候,就可以通过把x的颜色改成黑色来恢复红黑树的性质。当x结点为根结点的时候,由于结点x到其后代叶子结点的黑高都相等(由于可能做了好几次迭代使得x指向了根结点),所以只需要把结点x改成黑色就可以了。

 情况1:当结点x的兄弟结点w是红色的时候。因为删除结点之前这是一棵红黑树,所以结点w的父结点和孩子结点必定为黑色。这种情况把结点w改成黑色,把结点r改成红色,然后对结点r做左旋操作,然后把w指向结点x的新的兄弟结点。这个时候继续这次迭代,因为这个情况,只是把结点w为红色的情况转化成结点w为黑色的情况,后面的几种情况都是分析结点w为黑色的情况。

情况2:当结点x的兄弟结点w是黑色,而结点w的孩子结点都是黑色的时候。这个时候结点x的父结点的颜色是不确定的,所以我们用另外的颜色表示。把结点w改成红色,把x指向结点c。这个操作是为了使得结点c(迭代后的结点x)到左右后代叶子结点的黑高一致(因为原先结点x所在的路径上的黑高因为删除结点少1,那么结点x的兄弟结点的路径上少一个黑色结点就可以使得路径的黑高一致)。

情况3:当结点x的兄弟结点w是黑色,而结点w的右孩子结点是黑色的时候。因为是先判断了情况2,如果情况2不满足,而且w的右孩子结点是黑色的时候,那么w的左孩子结点必定是红色。针对这种情况。把结点w的左孩子结点改为黑色,结点w改为红色,对结点w做右旋操作。这个时候继续这次迭代,因为这个情况,只是把情况3转化成情况4。

情况4:当结点x的兄弟结点w是黑色,而且结点w右孩子结点是红色的时候。结点c‘是红色或者黑色的结点有可能与结点c的颜色也不一致,所以用另外的颜色表示。把结点w的右孩子结点改为黑色,把结点w改为结点c的颜色,把结点c改为黑色,然后对结点c做左旋操作,最后把x指向根结点。这个时候由于把结点x的路径上的黑高补全了,而且其它路径的黑高也没有变化,所以这个时候整棵红黑树的性质完整了,这次的迭代结束(其实整个调整操作也已经结束了,因为x已经指向了根结点)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值