最大最小值以及前驅後繼操作最壞情況都爲O(1)的順序統計樹

問題:通過爲結點增加指針的方式,試說明如何在擴張的順序統計樹上,支持每一動態集合查詢操作MINIMUM,MAXIMUM,SUCCESSOR和PREDECESSOR在最壞時間O(1)內完成。順序統計樹上的其他操作的漸近性能不應受影響。

代碼如下:

//本程序在原有的紅黑樹基礎上增加了子樹結點個數,前驅後繼結點以及最大小結點屬性。
#include <iostream>
#include <time.h>
using namespace std;
#define BLACK 0
#define RED 1
#define Nil -1
#define n  20 //更改順序統計樹內的結點數。
#define LEN sizeof(struct OS_Tree)
struct OS_Tree
{
   struct OS_Tree*right,*left;
   struct OS_Tree*parent;
   struct OS_Tree*next,*prev;
   struct OS_Tree* Max,*Min;
   int key,color,size;//size表示子樹的結點數。
};
struct OS_Tree*root=NULL,*nil=NULL,*head=NULL,*tail=NULL;
void LEFT_ROTATE(struct OS_Tree*x)
{//左旋轉:分三個步驟①②③來敘述旋轉代碼的。
	struct OS_Tree*y=x->right;//設置y結點。
	if(y->left!=nil)x->Max=y->left->Max;//對附加信息的維護
	else x->Max=x;
	y->Min=x->Min;
	x->right=y->left;//本行代碼以及下面的if結構表達的是“y的左孩子成爲x的右孩子”。①
	if(y->left!=nil)
	{
       y->left->parent=x;
	}
	y->parent=x->parent;//本行代碼以及下面的if-else結構表達的過程是“y成爲該子樹新的根”。②
	if(x->parent==nil)
	{
       root=y;
	}
	else if(x==x->parent->left)
	{
       x->parent->left=y;
	}
	else x->parent->right=y;
	y->left=x;//本行代碼以及下面一行都表達了“x成爲y的左孩子”。③
	x->parent=y;  
    y->size = x->size;  //對附加信息的維護
    x->size = x->left->size + x->right->size +1; 
}
void RIGHT_ROTATE(struct OS_Tree*x)
{//右旋轉:分三個步驟①②③來敘述旋轉代碼的。
	struct OS_Tree*y=x->left;//設置y結點。
	if(y->right!=nil) x->Min=y->right->Min;//對附加信息的維護
	else x->Min=x;
	y->Max=x->Max;
	x->left=y->right;//本行代碼以及下面的if結構表達的是“y的左孩子成爲x的右孩子”。①
	if(y->right!=nil)
	{
		y->right->parent=x;
	}
	y->parent=x->parent;//本行代碼以及下面的if-else結構表達的過程是“y成爲該子樹新的根”。②
	if(x->parent==nil)
	{
		root=y;
	}
	else if(x==x->parent->right)
	{
		x->parent->right=y;
	}
	else x->parent->left=y;
	y->right=x;//本行代碼以及下面一行都表達了“x成爲y的左孩子”。③
	x->parent=y;
	y->size = x->size;  //對附加信息的維護
    x->size = x->left->size + x->right->size +1; 
}
void RB_INSERT_FIXUP(struct OS_Tree*z)
{
   while (z->parent->color==RED)
   {
	   if (z->parent==z->parent->parent->left)
	   {
		   struct OS_Tree*y=z->parent->parent->right;//叔結點
		   if (y->color==RED)//情況一:叔結點爲紅色
		   {//給p1,y,p2着色以保持性質5。並且解決了z的父結點和z都是紅色結點問題
			   z->parent->color=BLACK;
			   y->color=BLACK;
			   z->parent->parent->color=RED;
			   z=z->parent->parent;//把z的祖父結點當成新結點z進入下一次循環
		   } 
		   else 
		   {
			   if (z==z->parent->right)//情況二:檢查z是否是一個右孩子且叔結點爲黑色,前提是p1結點不是葉子結點
			   {//使用一個左旋讓情況2轉變爲情況3
				   z=z->parent;
				   LEFT_ROTATE(z);//由於進入if語句後可知旋轉結點不可能是葉子結點,這樣就不用判斷z是否是葉子結點了。
			   } 
               z->parent->color=BLACK;//情況三:是z是一個左孩子且叔結點爲黑色,改變z的父和祖父結點顏色並做一次右旋,以保持性質5
			   z->parent->parent->color=RED;
			   RIGHT_ROTATE(z->parent->parent);//由於p2可能是葉子結點,所以最好還是用一個if判斷
		   }
	   } 
	   else//下面else分支類似於上面,注意到else分支的情況2和情況3所做旋轉正好是if分支情況的逆。
	   {
		   struct OS_Tree*y=z->parent->parent->left;
		   if (y->color==RED)
		   {
			   z->parent->color=BLACK;
			   y->color=BLACK;
			   z->parent->parent->color=RED;
			   z=z->parent->parent;
		   } 
		   else 
		   {
			   if (z==z->parent->left)
			   {
				   z=z->parent;
				   RIGHT_ROTATE(z);
			   } 
               z->parent->color=BLACK;
			   z->parent->parent->color=RED;
			   LEFT_ROTATE(z->parent->parent);
		   }
	   }
   }
   root->color=BLACK;//最後給根結點着爲黑色。
}
void RB_INSERT(struct OS_Tree*z)
{
	struct OS_Tree*y=nil;
	struct OS_Tree*x=root;
	while (x!=nil)
	{
		x->size++;
		y=x;  
		if (z->key<x->key)
		{
			x=x->left;
		}
		else x=x->right;
	}
	z->parent=y;
	if (y==nil)
	{
		tail=head=root=z;
		root->next=nil;
		root->prev=nil;
	} 
	else if(z->key<y->key)
	{
		y->left=z;
		z->next=y;
		y->prev=z;
		while (y)
		{ 
			y->Min=z;
			if (y->parent==nil||y->parent->right==y)
			{
				break;
			}
		   y=y->parent;
		}
		if (y->parent==nil)
		{
			head=z;
			z->prev=nil;
		}
		else if (y->parent->right==y)
		{
			y->parent->next=z;
		    z->prev=y->parent;
		}
	}
	else 
	{
		y->right=z;
		z->prev=y;
		y->next=z;
		while (y)
		{
			y->Max=z;
			if (y->parent==nil||y->parent->left==y)
			{
				break;
			}
			y=y->parent;
		}
		if (y->parent==nil)
		{
			tail=z;
			z->next=nil;
		}
		else if (y->parent->left==y)
		{
			y->parent->prev=z;
			z->next=y->parent;
		}
	}
	z->left=nil;//給插入結點左右孩子賦值爲空。
	z->right=nil;
	z->color=RED;//給插入結點着爲紅色。
	z->Max=z->Min=z;
	z->size=1;
	z->left->size=0;
	z->right->size=0;
	RB_INSERT_FIXUP(z);
	//InOderTraverse(root);
}
void RB_TRANSPLANT(struct OS_Tree*u,struct OS_Tree*v)
{
	if (u->parent==nil)
		root=v;
	else if(u==u->parent->left)
		u->parent->left=v;
	else u->parent->right=v;
	v->parent=u->parent;
}
struct OS_Tree*TREE_MINIMUM(struct OS_Tree*x)//求二叉查找樹當前結點最小值
{
	return x->Min;
}
struct OS_Tree*TREE_MAXINUM(struct OS_Tree*x)//求二叉查找樹當前結點最大值
{
	return x->Max;
}
struct OS_Tree*TREE_PREDECESSOR(struct OS_Tree*x)//查找二叉查找樹的前驅
{
	return x->prev;
}
struct OS_Tree*TREE_SUCCESSOR(struct OS_Tree*x)//查找二叉查找樹的後繼
{
	return x->next;
}
//非遞歸版本的二叉查找樹查找函數
struct OS_Tree*ITERATIVE_TREE_SEARCH(struct OS_Tree*x,int k)
{
	while (x!=nil&&k!=x->key)
	{
		if (k<x->key)
		{
			x=x->left;
		}
		else x=x->right;
	}
	return x;
}
void RB_DELETE_FIXUP(struct OS_Tree*x)
{
	
	 struct OS_Tree*w=NULL;//w是x的兄弟結點
     while (x!=root&&x->color==BLACK)//如果x是黑色並且不是根結點,才進行循環。
     {//x是一個具有雙重顏色的結點,調整的目的是把x的黑色屬性向上移動。
		 if (x==x->parent->left)
		 {
			 w=x->parent->right;
			 if (w->color==RED)//情況一:x的兄弟結點w是紅色的。
			 {//改變w和x.p的顏色+一次旋轉使其變爲情況二,三,四。
				 w->color=BLACK;
				 x->parent->color=RED;
				 LEFT_ROTATE(x->parent);
				 w=x->parent->right;
			 }
			 if (w->left->color==BLACK&&w->right->color==BLACK)//情況二:x的兄弟結點w是黑色的,而且w的兩個子節點都是黑色。
			 {
				 w->color=RED;//從x和w上去掉一重黑色。x還是黑色,而w變爲紅色。
				 x=x->parent;//x結點向上移動成爲新的待調整結點。
			 }
			 else
			 {
				 if (w->right->color==BLACK)//情況三:x的兄弟結點w是黑色的,w的左孩子是紅色的,w的右孩子是黑色的。
				 {//交換w和w.left的顏色+旋轉使其轉變爲情況四。
					 w->left->color=BLACK;
					 w->color=RED;
					 RIGHT_ROTATE(w);
					 w=x->parent->right;
				 }
				 w->color=x->parent->color;//以下是情況四:x的兄弟結點w是黑色的,且w的右孩子是紅色的。
				 x->parent->color=BLACK;//置x.p和w.right爲黑色+旋轉使其去掉x的額外黑色。
				 w->right->color=BLACK;
				 LEFT_ROTATE(x->parent);
				 x=root;//x成爲根結點,結束循環。
			 }
		 } 
		 else//以下和上面的if分支類似,不做累述。
		 {
             w=x->parent->left;
			 if (w->color==RED)
			 {
				 w->color=BLACK;
				 x->parent->color=RED;
				 RIGHT_ROTATE(x->parent);
				 w=x->parent->left;
			 }
			 if (w->left->color==BLACK&&w->right->color==BLACK)
			 {
				 w->color=RED;
				 x=x->parent;
			 }
			 else
			 {
				 if (w->left->color==BLACK)
				 {
					 w->right->color=BLACK;
					 w->color=RED;
					 LEFT_ROTATE(w);
					 w=x->parent->left;
				 }
				 w->color=x->parent->color;
				 x->parent->color=BLACK;
				 w->left->color=BLACK;
				 RIGHT_ROTATE(x->parent);
				 x=root;
			 }
		 }
     }x->color=BLACK;
}
void RB_DELETE(struct OS_Tree*z)
{
    struct OS_Tree*y=z,*x;//y爲待刪除或待移動結點
	int y_original_color=y->color;//保存y的原始顏色,爲做最後的調整做準備。
	struct OS_Tree*k=z->parent,*p=z->parent,*t=z->parent;
	if (z->left==nil)
	{
		while (t!=nil)
		{
			t->size--;
			t=t->parent;
		}
		x=z->right;//x指向y的唯一子結點或者是葉子結點,保存x的蹤跡使其移動到y的原始位置上
		if (z->parent->left==z)
		{
			if (x!=nil)
			{
				while (p!=nil&&p->parent->left==p)
				{
					p->Min=x->Min;
					p=p->parent;
				}
				p->Min=x->Min;
			} 
			else
			{
				while (p!=nil&&p->parent->left==p)
				{
					p->Min=k;
					p=p->parent;
				}
			    p->Min=k;
			}
		}
		else 
		{
			if (x!=nil)
			{
				while(p!=nil&&p->parent->right==p)
				{
                    p->Max=x->Max;
					p=p->parent;
				}
                p->Max=x->Max;
			} 
			else
			{
				while (p!=nil&&p->parent->right==p)
				{
					p->Max=k;
					p=p->parent;
				}
		        p->Max=k;
			}
		}
		RB_TRANSPLANT(z,z->right);//把以z.right爲根的子樹替換以z爲根的子樹。
	}
	else if (z->right==nil)
	{
		while (t!=nil)
		{
			t->size--;
			t=t->parent;
		}
		x=z->left;//x指向y的唯一子結點或者是葉子結點,保存x的蹤跡使其移動到y的原始位置上
		if(z->parent->right==z)
		{
			while (p!=nil&&p->parent->right==p)
			{
				p->Max=x->Max;
				p=p->parent;
			}
            p->Max=x->Max;
		}
		else 
		{
			while (p!=nil&&p->parent->left==p)
			{
				p->Min=x->Min;
				p=p->parent;
			}
             p->Min=x->Min;
		}
		RB_TRANSPLANT(z,z->left);//把以z.left爲根的子樹替換以z爲根的子樹。
	}
	else 
	{
		y=TREE_MINIMUM(z->right);//找到z.right的後繼。
		struct OS_Tree*t=y->parent;
		y->size=z->size-1;//y替換z原來的位置,所以size屬性在待刪除結點z基礎上-1
		while (t!=nil)
		{
			t->size--;
			t=t->parent;
		}
        y_original_color=y->color;//y的新的原始結點被重置。
		x=y->right;//x指向y的唯一子結點或者是葉子結點,保存x的蹤跡使其移動到y的原始位置上
		y->Min=z->left->Min;//+
		if (y->parent==z)
		{
			x->parent=y;//由於z的父結點是要刪除的結點,所以不能指向它,於是指向y
		} 
		else
		{
			struct OS_Tree*w=z->right;
			if (y->right!=nil)
			{
				while (w->left!=nil)
				{
					w->Min=x->Min;
					w=w->left;
				}
			}
			else
			{
				while (w->left!=nil)
				{
					w->Min=y->parent;
					w=w->left;
				}
			}
			y->Max=z->Max;//+
			RB_TRANSPLANT(y,y->right);//把以y.right爲根的子樹替換以y爲根的子樹。
			y->right=z->right;
			y->right->parent=y;
		}
		RB_TRANSPLANT(z,y);//把以y爲根的子樹替換以z爲根的子樹。
		y->left=z->left;
		y->left->parent=y;
		y->color=z->color;//把已經刪除的結點顏色賦值給y,保證了y以上的樹結構紅黑性質不變。
	}
	if (z->prev==nil)
	{
        head=z->next;
	}
	if (z->next==nil)
	{
		tail=z->prev;
	}
	z->prev->next=z->next;
	z->next->prev=z->prev;
	if(y_original_color==BLACK) //y的原始顏色爲黑色,說明需要調整紅黑顏色。
		RB_DELETE_FIXUP(x);
}
//中序遍歷
void InOderTraverse(struct OS_Tree *p)
{
    if (p!=nil)
	{		
		InOderTraverse(p->left);
		cout<<p->key<<" "<<p->color<<" "<<"最大值:"<<p->Max->key<<"最小值:"<<p->Min->key<<"秩:"<<p->size<<endl;
		InOderTraverse(p->right);
	}
}
int RAND(int a[],int i)//隨機選擇N個互不相同的數。
{
	int k=rand()%n+1;
	for (int j=0;j<i;j++)
	{
		if (a[j]==k)
		{
			k=rand()%n+1;
			j=-1;
		}
	}
	return k;
}
struct OS_Tree*OS_SELECT(struct OS_Tree*x,int i)//查找順序統計樹給定秩的元素
{
   int r=x->left->size+1;
   if (i==r)
   {
	   return x;
   }
   else if (i<r)
   {
	   return OS_SELECT(x->left,i);
   }
   else return OS_SELECT(x->right,i-r);
}
int OS_RANK(struct OS_Tree*T,struct OS_Tree*x)//確定順序統計樹的秩
{
   int r=x->left->size+1;
   struct OS_Tree*y=x;
   while (y!=root)
   {
	   if (y==y->parent->right)
	   {
		   r=r+y->parent->left->size+1;
	   }
	   y=y->parent;
   }
   return r;
}
void main()
{
	//srand( (unsigned)time( NULL ) );
	int array1[n]={0};
	for (int j=0;j<n;j++)
	{
		array1[j]=RAND(array1,j);
		cout<<array1[j]<<" ";
	}
	cout<<endl;
	nil=new struct OS_Tree[LEN];
	nil->key=Nil;nil->color=BLACK;
	root=nil;
	int i=0;
	struct OS_Tree*ROOT=new struct OS_Tree[LEN];
	ROOT->key=array1[i++];
	RB_INSERT(ROOT);
	root=ROOT;
    while (i!=n)
    {
		struct OS_Tree*z=new struct OS_Tree[LEN];
		z->key=array1[i];
		RB_INSERT(z);
		i++;
    }
	InOderTraverse(root);
	cout<<endl;
	struct OS_Tree*x=NULL;
	i=0;
	while(i!=n)
	{
		x=ITERATIVE_TREE_SEARCH(root,array1[i]);
		cout<<OS_RANK(root,x)<<endl;
		RB_DELETE(x);
		cout<<"刪除"<<array1[i++]<<"後中序遍歷:"<<endl;
		InOderTraverse(root);
	}
	cout<<endl;
}
總結:以上程序適當地對插入和刪除函數進行修改,修改部分只是增加了O(lgn)時間的常係數,比如在插入過程中,需要從葉結點向上遍歷到根結點,遍歷這段路徑只需O(lgn)時間,刪除函數也有類似情況。其他函數有的增加了常數時間,有的未作改動。總體來看,在增加新屬性的基礎上,除求最值和前驅後繼操作時間變爲O(1),其他操作漸進性能均不受影響。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章