紅黑樹刪除的實現

在將紅黑樹中某個節點刪除時,分幾個步驟,首先找到該節點的位置,而後刪除該節點,最後調整紅黑樹。node

本文代碼還存在一個問題沒有解決,當連續刪除到第3個節點時會出現問題,如今暫時還沒找出問題,之後有空慢慢研究。數據結構

一、找出要刪除的節點函數

TREE rb_delete_find(TREE r, int d)	// find the node that need deleted
{
	NODE *x;
	x = r;
	while(x != NULL)
	{
		if(x->key == d)
			break;
		else if(d < x->key)
			x = x->left;
		else
			x = x->right;
	}
	
	if(x == NULL)
	{
		printf("find failed\n", x->key);
		return NULL;
	}
	else
	{
		printf("find success, %d\n", x->key);
		return rb_delete(r, x);
	}
}

二、刪除節點

在找到要刪除的節點後,根據不一樣的情形將節點刪除。代碼以下:spa

TREE rb_delete(TREE r, NODE *z)
{
	NODE *x, *y = z, *tmp;
	int y_original_color = y->color;
	
	tmp = (TREE)malloc(sizeof(NODE));
	tmp->key = -1;
	tmp->color = 1;
	tmp->left = NULL;
	tmp->right = NULL;
	
	if(z->left == NULL)
	{
		x = z->right;
		r = rb_delete_node(r, z, z->right);
		if(x == NULL)
		{
			x = tmp;
			x->p = z->p;
			z->p->right = x;
		}
	}
	else if(z->right == NULL)
	{
		x = z->left;
		r = rb_delete_node(r, z, z->left);
		
	}
	else	//左右孩子都不爲空 
	{
		y = tree_minimum(z->right);			//y要麼沒有子節點要麼只有右孩子 
		y_original_color = y->color;
		x = y->right;
		
		if(y->p != z)
		{
			r = rb_delete_node(r, y, y->right);
			y->right = z->right;
			y->right->p = y;
		}
		r = rb_delete_node(r, z, y);
		y->left = z->left;
		y->left->p = y;
		y->color = z->color;
		
		if(NULL == x)
		{
			x = tmp;
			x->p = y;
			y->right = x;
		}
	}
//	printf("root->key: %d \tx->key: %d\n", r->key, x->key);
//	printf("root->left: %d \troot->right: %d\n", r->left->key, r->right->key);
	/**在刪除或移動黑色節點時,須要將他的黑色下推給他的孩子節點。若孩子節點爲空,
		這時將沒法將黑色下推。若黑色向上推則會致使黑高的不相等。
		在此經過建立臨時節點,將其做爲葉子節點。葉子節點的顏色爲黑色,值爲-1. 
	**/ 
	
	//printf("------------r.key = %d   x.key = %d\n",r->key, x->key);
	//y_original_color保存了移動或刪除的節點的顏色,當移動或刪除的節點爲紅色時,紅黑樹的性質沒有被破壞,
	//而當移動或刪除的節點爲黑色時,紅黑樹的性質被破壞了,這是就須要對其進行調整。 
	if(y_original_color == 1)	//1:黑色, 0:紅色  
	{
		r = rb_delete_fixup(r, x);
	}
	
	return r;
}

三、紅黑樹的調整

當刪除或移動的節點爲黑色時,須要對紅黑樹進行調整,以使得其繼續保持紅黑樹的性質。具體的調整過程見上一篇文章。code

調整代碼以下:blog

TREE rb_delete_fixup(TREE r, NODE *z)
{
	NODE *x = z, *w;
	
	while(x!=r && x->color==1)
	{
		if(x == x->p->left)		//x is left child
		{
			w = x->p->right;
			if(w!=NULL && w->color == 0)		//case 1: w->color=0
			{
				w->color = 1;
				x->p->color = 0;
				r = left_rotate(r, x->p);
				w = x->p->right;
			}
			
			//提取x和w的一個黑色, 上移到x的父節點。從w提出一個黑色後其變成了紅色,x還剩一個黑色 
			if((w->left==NULL ||w->left->color==1) && (w->right==NULL || w->right->color==1))	//case 2: w->color=1 && w.left=1 && w.right=1
			{
				w->color = 0;
				x = x->p;
			}
			else
			{
				if(w->right==NULL || w->right->color==1)						//case 3: w->color=1 && w.left=0 && w.right=1
				{
					w->left->color = 1;
					w->color = 0;
					r = right_rotate(r, w);
					w = x->p->right;
				}
				w->color = x->p->color;						//case 4: w->color=1 && w.right=0
				x->p->color = 1;
				w->right->color = 1;
				r = left_rotate(r, x->p);
				x = r;
			}
		}
		else					//x is right child
		{
			w = x->p->left;
			if(w->color == 0)	//case 1
			{
				w->color = 1;
				x->p->color = 0;
				r = right_rotate(r, x->p);
				w = x->p->left;
			}
			if((w->left==NULL || w->left->color==1) && (w->right==NULL || w->right->color==1))	//case 2
			{
				w->color = 0;
				x = x->p;
			}
			else
			{
				if(w->left==NULL || w->left->color==1)		//case 3
				{
					w->color = 0;
					w->right->color = 1;
					r = left_rotate(r, w);
					w = x->p->left;
				}
											//case 4
				w->color = x->p->color;
				w->left->color = 1;
				x->p->color = 1;
				
				r = right_rotate(r, x->p);
				x = r;
			}
		}
	}
	x->color = 1;
	return r;
}

在以上的過程當中還用到了如下函數,

首先是刪除節點函數,其代碼以下:ip

/**
**	刪除節點x,使用y來代替x節點 
**/
TREE rb_delete_node(TREE r, NODE *x, NODE *y)
{
	if(x->p == NULL)
	{
		r = y;
	}
	else if(x == x->p->left)
	{
		x->p->left = y;
	}
	else 
		x->p->right = y;
	
	if(y != NULL)
		y->p = x->p;
	
	return r;
}

其次是查找後繼節點的函數,代碼以下:

//查找節點z的後繼節點 
NODE *tree_minimum(NODE *z)
{
	NODE *x = z;
	while(x->left != NULL)
		x = x->left;
	
	return x;
}

其餘的如節點的數據結構,樹的左旋和右旋的具體實現函數,見紅黑樹的插入那篇文章。
相關文章
相關標籤/搜索