• 红黑树删除的实现


    在将红黑树中某个节点删除时,分几个步骤,首先找到该节点的位置,然后删除该节点,最后调整红黑树。

    本文代码还存在一个问题没有解决,当连续删除到第3个节点时会出现问题,现在暂时还没找出问题,以后有空慢慢研究。

    1、找出要删除的节点

    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
    ", x->key);
    		return NULL;
    	}
    	else
    	{
    		printf("find success, %d
    ", x->key);
    		return rb_delete(r, x);
    	}
    }

    2、删除节点

    在找到要删除的节点后,根据不同的情形将节点删除。代码如下:

    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 	x->key: %d
    ", r->key, x->key);
    //	printf("root->left: %d 	root->right: %d
    ", r->left->key, r->right->key);
    	/**在删除或移动黑色节点时,需要将他的黑色下推给他的孩子节点。若孩子节点为空,
    		这时将无法将黑色下推。若黑色向上推则会导致黑高的不相等。
    		在此通过创建临时节点,将其作为叶子节点。叶子节点的颜色为黑色,值为-1. 
    	**/ 
    	
    	//printf("------------r.key = %d   x.key = %d
    ",r->key, x->key);
    	//y_original_color保存了移动或删除的节点的颜色,当移动或删除的节点为红色时,红黑树的性质没有被破坏,
    	//而当移动或删除的节点为黑色时,红黑树的性质被破坏了,这是就需要对其进行调整。 
    	if(y_original_color == 1)	//1:黑色, 0:红色  
    	{
    		r = rb_delete_fixup(r, x);
    	}
    	
    	return r;
    }

    3、红黑树的调整

    当删除或移动的节点为黑色时,需要对红黑树进行调整,以使得其继续保持红黑树的性质。具体的调整过程见上一篇文章。

    调整代码如下:

    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;
    }

    在以上的过程中还用到了以下函数,

    首先是删除节点函数,其代码如下:

    /**
    **	删除节点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;
    }

    其他的如节点的数据结构,树的左旋和右旋的具体实现函数,见红黑树的插入那篇文章。


  • 相关阅读:
    软件测试面试题及答案【史上最全】
    Loadrunner参数(摘)
    Linux系统的目录结构
    关于梦想(七)
    Mysql基于Linux上的安装
    走进MySQL
    关于梦想(六)
    Jmeter的实例应用
    十种社会中最真实的人际关系
    有些人走了就走了,该在的还在就好
  • 原文地址:https://www.cnblogs.com/liuwu265/p/4100095.html
Copyright © 2020-2023  润新知