红黑树的插入和删除

       上一章讲述了红黑树得相关性质,我们了解到红黑树确实是平衡二叉树,在时间复杂度为O(lg(n)),比二叉搜索树性能更好,性能变好的前提是算法更加复杂了,下面讲述红黑树的插入和删除操作,希望对大家有所帮助。

红黑树的插入

          红黑树的插入操作和二叉搜索树大致相同,不同点是在将节点x插入红黑树后,此时的红黑树可能会违反红黑树的相关性质,我们需要对其进行调整,调整的方法有两种:变色和旋转。下面着重讲述一下旋转操作。

旋转

旋转分为左旋和右旋,具体示意图如下:
                                               
旋转变换不会改变红黑树的中序遍历。
由上图中旋转变换的原理,可以写出旋转变换的伪代码:
LEFT-ROTATE(T,x)
y=x.right
x.right=y.left
if y.left !=T.nil
    y.left.p=x
y.p=x.p
if(x.p==T.nil)
    T.root=y
elseif x==x.p.left
    x.p.left=y
else
    x.p.right=y
y.left=x;
x.p=y
旋转变换c代码:
void left_rotate(tree_node *x)                   //红黑树的左旋转
{       
	tree_node *y;
	y=x->right;
	x->right=y->left;
	if(y->left!=NULL)
	{	
		y->left->parent=x;
	}
	if(x->parent->left==x)
	{
		x->parent->left=y;
	}
	else
	{
		x->parent->right=y;
	}
	y->parent=x->parent;
	y->left=x;
	x->parent=y;
}
这里我们需要注意一点:当红色节点为单支节点时,该红色节点一定为为叶子节点。
在进行插入操作时,我们需要将插入节点的颜色赋成红色,因为红色节点插入后不会破坏红黑树性质5,但是仍然会破坏性质2或者性质4,但是仅仅出现一条性质的破坏。如果插入黑色节点,则破坏的性质位置
                                                                                                            
如下三种情况是不可能出现的:

                                                    
由红黑树的第五条性质可以知道,任意节点x的子分支结构都具有相同的黑高,如果是上述三种情况,不可能满足该性质。
综上所述,插入操作可以分为如下三种情况:
情况1:如果插入节点的父节点为黑色,则直接插入即可,不会影响红黑树的性质。
                                                                          
情况2:如果插入节点的父节点为红色,叔节点为红色时
                                                                                
情况3:如果插入节点的父节点为红色,叔节点为黑色,且待删除节点为父节点的有孩子
                      
这一步是为了将情况3变成情况4,再利用情况4的解决方法解决该问题

由此红黑树插入操作就结束了。
c代码如下:
void RB_insert(tree_node *x,tree_node *z)		//插入红黑树的一个节点
{
	tree_node *y,*y1;
	z->color=1;									//将插入节点设为红色
	y1=x;										//保留当前x的指针位置
	while(x!=NULL)								
	{
		y=x;
		if(x->data>z->data)
		{
			x=x->left;
		}
		else
		{
			x=x->right;
		}
	}
	if(y->data>z->data)						//判断z为左节点还是右节点
	{
		y->left=z;
	}
	else
	{
		y->right=z;
	}
	z->parent=y;
	z->left=NULL;
	z->right=NULL;
	RB_fix(z);
}
void RB_fix(tree_node *z)			//重新着色
{
	while(z->parent->color!=0)			//当红黑树性质恢复时,z节点一定为红色,则其父节点一定为黑色,作为循环结束标志
	{
		if(z->parent->parent->left==z->parent)	//判断父节点是否是祖父节点的左孩子
		{
			if(z->parent->parent->right->color==1)	//情况1,叔节点为红色
			{
				z->parent->color=0;
				z->parent->parent->color=1;
				z->parent->parent->left->color=0;
				z=z->parent->parent;
			}
			else if(z->parent->right==z)		//情况2,叔节点为黑色,且插入节点为父节点的右孩子
			{
				left_rotate(z);
			}
			else								//情况3,叔节点为黑色,且插入节点为父节点的左孩子
			{
				right_rotate(z);
				z->parent->color=0;
				z->parent->right->color=1;
			}
		}
		else									//判断父节点是否是祖父节点的左孩子
		{
				if(z->parent->parent->left->color==1)
				{
					z->parent->color=0;
					z->parent->parent->color=1;
					z->parent->parent->left->color=0;
					z=z->parent->parent;
				}
				else if(z->parent->left==z)
				{
					right_rotate(z);
				}
				else
				{
					left_rotate(z);
					z->parent->color=0;
					z->parent->left->color=1;
				}
		}
	}
}
删除操作算法导论上写的始终感觉有问题,以后看懂了再讲吧。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值