第一段标题

红黑树

下面网址中是红黑树很好的教材,很详细。

http://blog.csdn.net/eric491179912/article/details/6179908

另外经典教材就是算法导论中关于红黑树的章节了,以算法导论为主,实在不明白的地方再去网上查找资料。

红黑树是一种特殊的二叉查找树,大家都知道二叉查找树的复杂度最坏情况为O(h),为了减低最坏情况的复杂度,大神们设计了许多种二叉查找树的改进版本,红黑树便是其中之一,它可以保证在最坏情况下复杂度为O(lgn),也就是说h < lgn。

红黑树的五个性质

1)每个节点或者是红色,或者是黑色

2)根节点是黑色

3)每个叶子节点是黑色的(此处的叶子节点指的是外部节点)

4)红色节点的两个孩子都是黑色的

5)对于每个节点,从该节点到其子孙叶子节点的所有路径上包含相同数目的黑色节点

红黑树节点的定义

typedef struct node
{
	int color;
	int key;
	struct node *p;//指向父节点
	struct node *left, *right;

}RBtreeNode;

与二叉搜索树相比较,多出了2部分,本节点的颜色属性和指向父节点是指针,之所以需要指向父节点是为了后序操作的便利。

红黑树的左旋和右旋

在节点x上左旋,是以x和x的右孩子y之间的轴为支点,旋转结束后x成为y的左孩子;在节点y上右旋,是以y和y的左孩子x之间的轴为支点,旋转结束后y是x的右孩子;如图所示

   ,理论上与二叉搜索树的旋转没有任何区别

红黑树的插入

假设新插入节点z,我们将其置为红色,可能破坏性质2)和性质4),违反性质2)是因为新插入的点成为了根节点,违反性质4)是因为z->p也是红色;插入z后,从底向上逐层调整树的结构和颜色,使其仍然满足红黑树的性质。既然从底层开始调整,我们可以只考虑违反性质4),当然在调整过程中绝不允许出现违反其他性质的现象。

前提z的父亲是红色

case1--z的叔叔是红色

z的叔叔uncle_z是红色,那z的爷爷肯定是黑色,可以把z的父亲和叔叔置为黑色,z的爷爷置为红色,z <- z的爷爷,然后继续向上操作。

case2--uncle_z是黑色,且z和uncle_z不是同一方向的孩子,即z是左孩子,uncle_z是右孩子;或者z是右孩子,uncle_z是左孩子

  case2.1--z是左孩子,uncle_z是右孩子,如下面左图所示。我们以z的爷爷为输入,做一次右旋操作,同时把parent_z置为黑色,gparent_z置为红色,整棵树调整结束。

     左右分割   

  case2.2--z是右孩子,uncle_z是左孩子,如上面右图所示。我们,以z的爷爷为输入,做一次左旋操作,同时把parent_z置为黑色,gparent_z置为红色,整棵树调整结束。

 可以看到,case2.1和case2.2是对称的两种情况。

case3--uncle_z是黑色,且z和uncle_z是同一方向的孩子,即z是左孩子,uncle_z也是左孩子;或者z是右孩子,uncle_z也是右孩子

   case3.1--z和uncle_z同时是左孩子,如下面左图所示。我们以z的父亲为输入,做一次右旋操作,同时把z置为旋转前z的父亲,变成了case2.2,有木有!!

  左右分割  

  case3.2--z和uncle_z同时是右孩子,如上面右图所示。我们以z的父亲为输入,做一次左旋操作,同时把z置为旋转前z的父亲,变成了case2.1。

插入的最后,在把root的颜色置为黑色,完事。

 红黑树的删除

假设被删除节点是z,可以找到真正要被删除的节点y,即如果z至多有一个孩子,y等于z;否则y是z的中序后继,此时y至多有一个右孩子;总的说来y至多只有一个右孩子x。如果y是红色,删除y后仍然能够保证红黑树的5个性质;如果y是黑色,可能违反性质2),4),5)。删除y时就是把x代替了y的位置,我们可以给x额外增加一个黑色,使其成为了双黑色和红黑色,这样满足了性质5),但违反性质1)。

如果x是红黑色,我们将其置为黑色,调整结束;

如果x是根节点,我们将其置为黑色,结束;

如果x是双黑色,做必要的旋转和涂色。

假设parent_x为删除节点y后x的父节点,实际上就是y的父节点,那么parent_x一定是有两个孩子的,因为此时y非空,且y是黑色,在不违反性质5)的前提下,y一定有兄弟。令parent_x的另一个孩子为w,即x的兄弟为w

case1--w为黑色,且w的两个孩子都是黑色

因为w是黑色,x是双重黑色,可以同时去掉x和w的黑色,x的父节点增加一重黑色,不会违反性质5),然后把x赋值给x的父节点,继续循环。如下面两幅图所示

    左右分割  

 case2--w是黑色,且w同一方向的孩子是红色,即若w是左孩子,w的左孩子是红色;若w是右孩子,w的右孩子是红色。我们可以通过旋转使x的高度减一,并且在x和x的父亲之间增加一个黑色节点,最后把x置为根节点,循环结束

  case2.1--w是黑色,w是左孩子,w的左孩子是红色,以w的父节点为输入,做一次左旋,并且做一些颜色涂改

   左右分割   

   case2.2--w是黑色,w是右孩子,w的右孩子是红色,以w的父节点为输入,做一次右旋,并且做一些颜色涂改

 case3--w是黑色,w同一方向的孩子是黑色,我们可以通过旋转使其转化为case2

  case3.1--w是黑色,w是左孩子,w的左孩子是黑色,那么右孩子一定是红色,否则就成了case1;以w为输入,做一次右旋,变成了case2.1

    左右分割  

  case3.2--w是黑色,w是右孩子,w的右孩子是黑色,那么左孩子一定是红色,否则就成了case1;以w为输入,做一次左旋,变成了case2.2

  case4--w是红色的,则w肯定有黑孩子,parent_x是黑色的,以parent_x为输入,做一次左旋,可转变成case1,case2,或者case3

 

 附源代码,另附测试数据的大神博客网址:http://blog.csdn.net/v_JULY_v/article/details/6284050

//红黑树基本操作
#include <stdio.h>
#include <list>

#define BLACK 0
#define RED 1
typedef struct node
{
	int color;
	int key;
	struct node *p;
	struct node *left, *right;

}treeNode;

//在节点x上左旋操作,以x和x右孩子之间的轴为支点,旋转结束后x成为y的左孩子
//      x                  y
//     / \   left_rotate  / \ 
//    lx  y     --->     x  ry
//       / \            / \
//      ly ry          lx ly
treeNode* left_rotate(treeNode* root, treeNode* x)
{
	treeNode *y = x->right;
	x->right = y->left;
	if(y->left != NULL)
		(y->left)->p = x;
	y->p = x->p;
	if(x->p == NULL)//x是根节点
		root = y;
	else if(x == (x->p)->left)
		(x->p)->left = y;
	else (x->p)->right = y;
	y->left = x;
	x->p = y;

	return root;
}

//在节点y上的右旋操作,以y和y的左孩子x之间的轴为支点,旋转结束后y是x的右孩子
//      y                  x
//     / \  right_rotate  / \ 
//    x  ry     --->     lx  y
//   / \                    / \          
//  lx rx                  rx ry
treeNode* right_rotate(treeNode* root, treeNode* y)
{
	treeNode *x = y->left;
	y->left = x->right;
	if(x->right != NULL)
		(x->right)->p = y;
	x->p = y->p;
	if(y->p == NULL)//y是根节点
		root = x;
	else if(y == (y->p)->left)
		(y->p)->left = x;
	else (y->p)->right = x;
	x->right = y;
	y->p = x;
	return root;
}

//插入新的节点后必须得调整
treeNode* rb_insert_fixup(treeNode *root, treeNode *z)
{
	treeNode *uncle_z;
	while(z->p && z->p->color == RED && z->p->p)
	{
		if (z->p->p->left == z->p)//z的父亲是左孩子
		{
			uncle_z = z->p->p->right;//z的叔父是右孩子
			//case1--叔父是右孩子,红色
			if(uncle_z && uncle_z->color == RED)
			{
				uncle_z->color = BLACK;
				z->p->color = BLACK;
				z->p->p->color = RED;
				z = z->p->p;
			}
			//case1 end
			else
			{	
				//case2--叔父是右孩子,黑色 z是右孩子
				if (z == z->p->right)//如果z是右孩子
				{
					z = z->p;
					root = left_rotate(root, z);
				}
				//case2 end 
				//case3--叔父是右孩子,黑色 z是左孩子
				z->p->color = BLACK;
				z->p->p->color = RED;
				root = right_rotate(root, z->p->p);
				//case3 end
			}
		}
		else//z的父亲是右孩子
		{
			uncle_z = z->p->p->left;//z的叔父是左孩子
			//case4--叔父是左孩子,红色
			if (uncle_z && uncle_z->color == RED)
			{
				uncle_z->color = BLACK;
				z->p->color = BLACK;
				z->p->p->color = RED;
				z = z->p->p;
			}
			//case4 end
			else 
			{	
				//case5--叔父是左孩子,黑色,z是左孩子
				if (z == z->p->left)
				{
					z = z->p;
					root = right_rotate(root, z);
				}
				//case5 end
				//case6--叔父是左孩子,黑色 z是右孩子
				z->p->color = BLACK;
				z->p->p->color = RED;
				root = left_rotate(root, z->p->p);
				//case6 end
			}
		}
	}
	root->color = BLACK;
	return root;
}

//插入新的节点
treeNode* rb_insert(treeNode *root, int value)
{
	treeNode *z = new treeNode;
	z->key = value;
	treeNode *x = root;
	treeNode *y = NULL;

	while(x != NULL)
	{
		y = x;
		if(value == x->key)
			return root;
		if(value < x->key)
			x = x->left;
		else x = x->right;
	}
	z->p = y;
	if (y == NULL)
	{
		root = z;
	}
	else
	{
		if(value < y->key)
			y->left = z;
		else
			y->right = z;
	}
	z->left = NULL;
	z->right = NULL;
	z->color = RED;
	root = rb_insert_fixup(root, z);
	return root;
}
//删除节点x的父节点后调整, x相当于多重黑色或者红黑色
treeNode* rb_delete_fixup(treeNode *root, treeNode *x, treeNode *parent_x)
{
	treeNode *w;//x_brother
	while(x!=root && (x == NULL ||x->color == BLACK))
	{
		//x的父亲parent_x一定有两个孩子
		if(x == parent_x->left)
		{
			w = parent_x->right;//x的右兄弟w
			//case1--x的兄弟w为红色,则w肯定有黑孩子,左旋,转换成case2,case3....
			if(w->color == RED)
			{
				w->color = BLACK;
				parent_x->color = RED;
				root = left_rotate(root, parent_x);
				w = parent_x->right; //w重新置为parent_x的右孩子
			}
			//case1 end
			//case2--w为黑色,w的两个孩子(如果有)也是黑色
			if((w->left == NULL || w->left->color == BLACK) && (w->right == NULL || w->right->color == BLACK))
			{
				w->color = RED;
				x = parent_x;
				parent_x = parent_x->p;
			}
			//case2 end	
			else
			{	//case3--w的右孩子是黑色,左孩子是红色
				if(w->right == NULL || w->right->color == BLACK)
				{
					if(w->left != NULL)//如果w有左孩子,一定是红色
						w->left->color = BLACK;
					w->color = RED;
					root = right_rotate(root, w);
					w = parent_x->right;
				}
				//case3 end
				//case4 w的右孩子是红色
				if (w->right != NULL)//如果w有右孩子,一定是红色
					w->right->color = BLACK;
				w->color = parent_x->color;
				parent_x->color = BLACK;	
				root = left_rotate(root, parent_x);
				x = root;
			}
		}
		else//与上面对称
		{
			w = parent_x->left;//x的左兄弟w
			//case5--x的兄弟w为红色,则w肯定有黑孩子,右旋,转换成case2,case3....
			if(w->color == RED)
			{
				w->color = BLACK;
				parent_x->color = RED;
				root = right_rotate(root, parent_x);
				w = parent_x->left;
			}
			//case5 end
			//case6--w为黑色,w的两个孩子(如果有)也是黑色
			if((w->left == NULL || w->left->color == BLACK) && (w->right == NULL || w->right->color == BLACK))
			{
				w->color = RED;
				x = parent_x;
				parent_x = parent_x->p;
			}
			//case6 end
			else
			{
			//case7--w的左孩子是黑色,右孩子是红色
				if(w->left == NULL || w->left->color == BLACK)
				{
					if(w->right != NULL)
						w->right->color = BLACK;
					w->color = RED;
					root = left_rotate(root, w);
					w = parent_x->left;
				}
				//case7 end
				//case8 w的左孩子是红色
				if (w->left->color == RED)
					w->left->color = BLACK;
				w->color = parent_x->color;
				parent_x->color = BLACK;	
				root = right_rotate(root, parent_x);
				x = root;
				//case8 end
			}
		}
	}

	if(x != NULL)
		x->color = BLACK;
	return root;
}

treeNode* rb_delete(treeNode *root, int value)
{
	treeNode *z, *y, *x;
	z = root;
	while(z != NULL)
	{
		if(z->key == value)
			break;
		if(z->key < value)
			z = z->right;
		else
			z = z->left;
	}
	if(z == NULL) //木有找到要删除的节点
		return root;
	y = z;
	if(y->left!=NULL && y->right!=NULL)//两个孩子的情况,y是z的中序后继
	{
		y = y->right;
		while (y->left != NULL)
		{
			y = y->left;
		}
		z->key = y->key;
	}
	//x是y唯一的孩子或者NULL
	if(y->left != NULL)
		x = y->left;
	else x = y->right;
	
	if(x)
		x->p = y->p;
	if(y->p == NULL)//y是根节点
		root = x;
	else if(y == y->p->left)
		y->p->left = x;
	else y->p->right = x;
	
	if(y->color==BLACK)
		root = rb_delete_fixup(root, x, y->p);
	delete y;
	return root;
}

treeNode* rb_find(treeNode *root, int value)
{
	treeNode *x = root;
	int h = 0;
	while (x != NULL)
	{
		if (x->key == value)
		{
			if(x->color == RED)
				printf("RED ");
			else
				printf("BLACK ");
			printf("从0层计数,%d在第%d层\n", value, h);
			return x;
		}
		if (x->key < value)
			x = x->right;
		else x = x->left;
		h++;
	}
	return NULL;
}

void midOrder(treeNode *root)
{
	if(root == NULL)
		return;
	midOrder(root->left);
	printf("%d-", root->key);
	if(root->color == RED)
		printf("RED ");
	else
		printf("BLACK ");
	midOrder(root->right);
}

void preOrder(treeNode *root)
{
	if(root == NULL)
		return;
	printf("%d-", root->key);
	if(root->color == RED)
		printf("RED ");
	else
		printf("BLACK ");
	preOrder(root->left);
	preOrder(root->right);
}


int main()
{
	int select, a;
	treeNode *root = NULL;
	do 
	{
		printf("请输入选择 1--插入,2--查询, 3--删除, 4--输出中序和前序,其他跳出\n");
		scanf("%d", &select);
		if (select == 1)
		{
			printf("输入将要插入的值, -1表示结束\n");
			while(scanf("%d", &a), a != -1)
			{
				root = rb_insert(root, a);
			}
		}
		else if (select == 2)
		{
			printf("输入将要查询的值, -1表示退出查询\n");
			while(scanf("%d", &a), a != -1)
			{
				if(rb_find(root, a) != NULL)
				{
					//printf("找到了\n");
				}
				else
					printf("木有找到\n");
			}
		}
		else if(select == 3)
		{
			printf("输入将要删除的值, -1表示退出删除\n");
			while(scanf("%d", &a), a != -1)
			{
				root = rb_delete(root, a);
			}
		}
		else if(select == 4)
		{
			printf("中序是:\n");
			midOrder(root);
			printf("\n前序是:\n");
			preOrder(root);
			printf("\n");
		}
		else break;

	} while (true);
	

	getchar();
	return 0;
}

运行结果,据小雨自己测试没有错误,欢迎大家前来拍砖

posted @ 2014-03-07 10:53  小雨淅淅  阅读(538)  评论(0编辑  收藏  举报