不带父结点的红黑树实现

      因为仅仅看到13.3节,所以临时仅仅实现旋转插入函数。

思考:假设不带父结点,那么在须要訪问z的父结点时,我们能够借助查找函数从根结点到待查找结点z的路径上必定能找到z的父结点和祖父结点,所以由此可訪问父结点。只是这样的方法使得旋转函数时间添加到O(lgn),而插入函数也对应的添加到O(lgnlgn)。节省了空间上的内存,同一时候添加了执行时间。

详细代码例如以下:

#include <iostream>
using namespace std;
#define BLACK 0
#define RED 1
#define Nil -1
#define LEN sizeof(struct Tree)
struct Tree
{
   struct Tree*left;
   struct Tree*right;
   int key;
   int color;
};
struct Tree*root=NULL;
struct Tree*nil=NULL;
//非递归版本号的二叉查找树查找函数
struct Tree*ITERATIVE_TREE_SEARCH(struct Tree*x,int k,struct Tree*&p1,struct Tree*&p2)
{//
	while (x!=nil&&k!=x->key)
	{
		p1=x;
		if (k<x->key)
		{
			x=x->left;
		}
		else x=x->right;
		if(k!=x->key)//假设没找到了待查找值,那么继续记录其祖父和父结点值。
		{
            p2=p1;
			p1=x;
		}
	}
	return x;
}
void LEFT_ROTATE(struct Tree*T,struct Tree*x)
{//左旋转:分三个步骤①②③来叙述旋转代码的。
	struct Tree*p1=nil,*p2=nil; 
	struct Tree*y=x->right;//设置y结点。
	x->right=y->left;//本行代码以及以下的if结构表达的是“y的左孩子成为x的右孩子”。① 
	ITERATIVE_TREE_SEARCH(root,x->key,p1,p2);
	if(p1==nil)//本行代码以及以下的if-else结构表达的过程是“y成为该子树新的根”。②
	{
       root=y;
	}
	else if(x==p1->left)
	{
       p1->left=y;
	}
	else p1->right=y;
	y->left=x;//本行代码以及以下一行都表达了“x成为y的左孩子”。③
}
void RIGHT_ROTATE(struct Tree*T,struct Tree*x)
{//右旋转
	struct Tree*p1=nil,*p2=nil; 
	struct Tree*y=x->left;
	x->left=y->right; 
	ITERATIVE_TREE_SEARCH(root,x->key,p1,p2);
	if(p1==nil)
	{
		root=y;
	}
	else if(x==p1->right)
	{
		p1->right=y;
	}
	else p1->left=y;
	y->right=x;
}
void RB_INSERT_INSERT_FIXUP(struct Tree*T,struct Tree*z)
{
   struct Tree*p1=nil,*p2=nil;  
   ITERATIVE_TREE_SEARCH(root,z->key,p1,p2);//p1=z->parent,p2=z->parent->parent
   while (1)
   {
	   ITERATIVE_TREE_SEARCH(root,z->key,p1,p2);//p1是父结点 p2是祖父结点
	   if (p1->color!=RED)
	   {
		   break;
	   }
	   if (p1==p2->left)
	   {
		   struct Tree*y=p2->right;//叔结点
		   if (y->color==RED)//情况一:叔结点为红色
		   {//给p1,y,p2着色以保持性质5。而且攻克了z的父结点和z都是红色结点问题
			   p1->color=BLACK;
			   y->color=BLACK;
			   p2->color=RED;
			   z=p2;//把z的祖父结点当成新结点z进入下一次循环
		   } 
		   else 
		   {
			   if (z==p1->right)//情况二:检查z是否是一个右孩子且叔结点为黑色,前提是p1结点不是叶子结点
			   {//使用一个左旋让情况2转变为情况3
				   z=p1;
				   LEFT_ROTATE(T,z);//因为进入if语句后可知旋转结点不可能是叶子结点,这样就不用推断z是否是叶子结点了。
			    ITERATIVE_TREE_SEARCH(root,z->key,p1,p2);//p1=z->parent,p2=z->parent->parent
			   } 
               p1->color=BLACK;//情况三:是z是一个左孩子且叔结点为黑色,改变z的父和祖父结点颜色并做一次右旋,以保持性质5。
			   p2->color=RED;
			   if(p2!=nil) RIGHT_ROTATE(T,p2);//因为p2可能是叶子结点,所以不妨用一个if推断
		   }
	   } 
	   else//以下else分支相似于上面
	   {
		   struct Tree*y=p2->left;
		   if (y->color==RED)
		   {
			   p1->color=BLACK;
			   y->color=BLACK;
			   p2->color=RED;
			   z=p2;
		   } 
		   else 
		   {
			   if (z==p1->left)
			   {
				   z=p1;
				   RIGHT_ROTATE(T,z);
				   ITERATIVE_TREE_SEARCH(root,z->key,p1,p2);
			   } 
               p1->color=BLACK;
			   p2->color=RED;
			   if(p2!=nil) LEFT_ROTATE(T,p2);
		   }
	   }
   }
   root->color=BLACK;//最后给根结点着为黑色。
}
void RB_INSERT(struct Tree*T,struct Tree*z)
{
	struct Tree*y=nil;
	struct Tree*x=root;
	while (x!=nil)
	{
		y=x;
		if (z->key<x->key)
		{
			x=x->left;
		}
		else x=x->right;
	}
	if (y==nil)
	{
		root=z;
	} 
	else if(z->key<y->key)
	{
		y->left=z;
	}
	else y->right=z;
	z->left=nil;
	z->right=nil;
	z->color=RED;
	RB_INSERT_INSERT_FIXUP(T,z);
}
//中序遍历
void InOderTraverse(struct Tree *p)
{
    if (p!=nil)
	{		
		InOderTraverse(p->left);
		cout<<p->key<<" "<<p->color<<" "<<endl;
		InOderTraverse(p->right);
	}
}
void main()
{
	nil=new struct Tree[LEN];
	nil->key=Nil;nil->color=BLACK;
	root=nil;
	int i=0;
	struct Tree*ROOT=new struct Tree[LEN];
	cin>>ROOT->key;
	RB_INSERT(nil,ROOT);
	root=ROOT;
    while (i!=12)
    {
		struct Tree*z=new struct Tree[LEN];
		cin>>z->key;
		RB_INSERT(root,z);
		i++;
    }
	InOderTraverse(root);
}


posted @ 2014-11-08 14:34  lcchuguo  阅读(303)  评论(0编辑  收藏  举报