红黑树的删除与维护

算法分析

         删除z节点(假设要删除z节点):

         case1:z为叶子时,删除z后,直接将z的叶子节点连接到z的父节点。

         case2:z只有一个孩子(非空)时,删除z后,将z的非空孩子直接连接到z的父节点。如图1所示。

 

图1.删除case2

case3:z的两个孩子均为非空,此时首先找z的中序后继,即找z的右子树中最左下节点y;然后删除y,将y的内容copy到z中,再将y的右子树连到y的父节点左下。

                       如图2所示。


2.删除case3

以上三种情况,删除红点不影响,删除黑点需要维护。

维护算法:

假设x是y的唯一孩子或者是叶子节点。将y(对于删除case1和case2为z)的黑色涂到x上(先不管x的颜色)。于是,

若x为红,只要将其涂黑,维护即可终止;

若x为黑,将y的黑色涂上之后,x则是一个双黑节点,违反了红黑树性质1。

处理步骤:

  • 若x为根,直接移去多余的一层黑色(树黑高减一),终止;
  • 若x为红,将y的黑色涂到x上,终止;
  • 若x为非根节点,且为黑色,则将y的黑色涂到x上,x变为双黑。通过变色,旋转,使多余的黑色向上传播,直到某个红色节点或传到根。
对于上边第三个步骤,x变为双黑后,分情况进行讨论维护,根据x是其父节点的左右孩子,分为8中情况,这里讨论x是其父节点的左孩子的4种情况。
以下所有情况中R代 表红,B代表黑。
case1:x的兄弟w为红色。如图3所示。
             
图3.维护case1
case2:x的黑兄弟w的两个孩子均为黑。如图4所示。
4.维护case2
case3:x的黑兄弟w的右子为黑,左子为红。如图5所示。
5.维护case3
case4:x的黑兄弟w的右子为红,左子为黑或红,如图6所示。
6.维护case4
算法实现(C语言)
定义的数据结构:
typedef struct RBTNode
{
    int key;
    struct RBTNode *parent,*left,*right;
    int color;
    //int size;
}RBTNode,*RBTree;
删除算法:
void RBTreeDelete(RBTree z)
{
	RBTree x,y;
	if(z->left == nil || z->right == nil)
		y = z;
	else 
		y=TreeSuccessor(z);   //y为z的中序后继

	if(y->left != nil)
		x = y->left;
	else
		x = y->right;

	x->parent = y->parent;
	if(y->parent == nil)
		root = x;
	else
	{
		if(y == y->parent->left)
			y->parent->left  = x;
		else
			y->parent->right = x;
	}
	if(y != z)
		z->key = y->key;
	if(y->color == BLACK)
		RBTreeDeleteFixup(x);
	free(y);    //VC6.0下这句好像有问题,可注释掉。
}
删除后维护:
void RBTreeDeleteFixup(RBTree x)
{
	RBTree w;
	while(x != root && x->color == BLACK){
		if(x == x->parent->left){
			w = x->parent->right;
			if(w->color == RED){										//case 1
				w->color = BLACK;
				x->parent->color = RED;
				LeftRotate(x->parent);
				w = x->parent->right;
			}
			if(w->left->color == BLACK && w->right->color == BLACK){       //case 2	
				w->color = RED;
				x = x->parent;
			}
			else{			
				if(w->right->color == BLACK){			       //case 3
					w->left->color = BLACK;
					w->color       = RED;
					RightRotate(w);
					w = x->parent->right;
				}
				w->color = x->parent->color;			       //case 4
				x->parent->color = BLACK;
				w->right->color  = BLACK;
				LeftRotate(x->parent);
				x = root;
			}
		}
		else{
			w = x->parent->left;
			if(w->color == RED){
				w->color = BLACK;
				x->parent->color = RED;
				RightRotate(x->parent);
				w = x->parent->left;
			}
			if(w->left->color == BLACK && w->right->color == BLACK){
				w->color = RED;
				x = x->parent;
			}
			else{ 
				if(w->right->color == BLACK){
					w->left->color = BLACK;
					w->color       = RED;
					LeftRotate(w);
					w = x->parent->left;
				}
				w->color = x->parent->color;
				x->parent->color = BLACK;
				w->left->color   = BLACK;
				RightRotate(x->parent);
				x = root;
			}
		}
	}    //endwhile
	x->color = BLACK;
}
查找z的中序后继:
RBTree TreeSuccessor(RBTree z)
{
	RBTree x;

	x = z->right;
	while(x->left != nil)
		x = x->left;

	return x;
}

最后,对于想验证一下,可以参考我的上篇博客: 建立红黑树(左旋、右旋、插入、维护)代码+验证,谢谢!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值