紅黑樹(Red BlackTree)的實現

      前面我們講解了簡單二叉查找樹、AVL樹,伸展樹,對於一棵高度爲h的二叉查找樹,其動態集合操作Search、Minimum、Maximum、Successor、Predecessor、Insert、Delete的運行時間爲θ(h),樹的高度決定了在樹上操作的成本。

一些常見的搜索樹的高度:

平衡二叉搜索樹:O(lgn)

1962年提出的AVL樹:<=1.44lgn

1972年提出的紅黑樹:<=2lg(n+1)

      紅黑樹是通過對二叉查找樹結點上增加一個存儲位表示結點的顏色(紅色或黑色) 通過對任何一條從根到葉子的路徑上各個結點着色方式的限制,確保沒有一條路徑會比其他路徑長出兩倍,從而接近平衡。

一、紅黑樹的性質

1、紅黑樹的定義

紅黑樹是滿足如下性質的二叉查找樹:

(1) 每個結點必須爲紅色或黑色。

(2) 根爲黑色。

(3) 樹中的nil葉子爲黑色。

(4) 若結點爲紅,則其兩個子孩子必爲黑。

(5) 對每個結點,從該結點到其子孫結點的所有路徑上包含相同數目的黑結點。

2、黑高度

從某個結點x出發(不包括該結點)到達一個葉結點的任意一條路徑上,黑色結點的個數稱爲該結點x的黑高度,用bh(x)表示。

3、紅黑樹的黑高度

紅黑樹的黑高度定義爲其根結點的黑高度,記爲bh(root[T]).。

4、紅黑樹的高度

一棵含n個內結點的紅黑樹的高度至多爲2lg( n+1) 。(證明請看算法導論)

二、紅黑樹的實現

1、原理請看參考資料[1]、[2]、[3]

2、下面給出的C++實現是完全按照算法導論上的僞代碼來的。參考資料[4]中給出了自頂向下紅黑樹的部分實現(未提供刪除操作),採用的是不含父節點指針的結點結構,但是實現複雜,不是很好理解。

3、實現代碼

#include <cstdlib>
#include <iostream>

using namespace std;

template <typename Comparable>
class RBTree
{
	public:
		
		RBTree()
		{
			nil = new RBTreeNode;//哨兵結點爲黑色 
			nil->parent = nil;
			nil->lchild = nil;
			nil->rchild = nil;
			root = nil;		
		}
		~RBTree()
		{
			makeEmpty(root);
			delete nil;
		}
		
		void preOrderTraverse()const
		{
			preOrderTraverse(root);	
		}
		
		void inOrderTraverse()const
		{
			inOrderTraverse(root);
		}
		
		void printTree()const
		{
			cout<<"preOrder :"<<endl;
			preOrderTraverse();
			cout<<endl;
			
			cout<<"inOrder :"<<endl;
			inOrderTraverse();
			cout<<endl<<endl;
		}
		
		//將元素插入紅黑樹中 
		bool insert(const Comparable& elem)
		{
			RBTreeNode* y = nil;	//y記錄當前結點的父結點 
			RBTreeNode* x = root;		//從根結點開始掃描,尋找插入點 
			
			while(x != nil)
			{
				y = x;
				if(elem < x->data)	//當前結點左子樹中繼續掃描 
				{
					x = x->lchild;
				}
				else if(x->data < elem)
				{
					x = x->rchild;	//當前結點右子樹中繼續掃描 
				}
				else
				{
					return false;			//樹中已存在該元素 
				}
			}
			//準備插入該元素 
			RBTreeNode* z = new RBTreeNode(elem);
			z->parent = y;					//y是z的雙親 
			if(y == nil)					//z插入空樹 
			{
				root = z;						//z爲新的根結點 
			}
			else if(elem < y->data)
			{
				y->lchild = z;				//z爲y的左孩子 
			}
			else
			{
				y->rchild = z;				//z爲y的右孩子 
			}
			z->lchild = nil;
			z->rchild = nil;
			z->color = RED;
			insertFixup(z);					//插入後調整 
			return true; 
		}
		
		//從紅黑樹中刪除一個元素		
		bool remove(const Comparable& elem)
		{
			RBTreeNode* z = search(elem, root);//查找結點 
			RBTreeNode* y;		//y爲要刪除的結點
			RBTreeNode* x;		//y的孩子結點 
				
			if(z != nil)
			{
				if(z->lchild == nil || z->rchild == nil)//case1 2
				{
					y = z;
				}
				else	//左右子樹均不空 case 3
				{
					y = successor(z);//後繼y的左子樹必然爲空(nil) 
				}
				//確定y的孩子結點(待連接到p[y]) 
				if(y->lchild != nil)
				{
					x = y->lchild;
				}
				else
				{
					x = y->rchild;
				}
				
				x->parent = y->parent;
				if(y->parent == nil)//y爲根結點 
				{
					root = x;
				}
				else if(y == y->parent->lchild)
				{
					y->parent->lchild = x;
				}
				else
				{
					y->parent->rchild = x;
				}
				
				if(y != z)//case 3
				{
					z->data = y->data;
				}
				
				if(y->color == BLACK)//刪除結點爲黑色,重新調整 
				{
					removeFixup(x);
				}
				
				delete y;
				return true;
			}
			return false;				//樹中不存在該結點 
		}
		
		bool search(const Comparable& elem)const
		{
			if(search(elem, root)!= nil)
			{
				return true;
			}
			return false;
		}
		
		bool isEmpty()
		{
			return root == nil;
		}
		
		/*求某一元素的後繼,前驅類似 
		 *應該確保樹非空,且樹中存在該元素 
		 否則拋出異常(這裏不做處理) 
		 */
		Comparable successor(const Comparable& elem)
		{
			RBTreeNode* z = search(elem, root);//查找結點
			if(z != nil)
			{
				return z->data;
			}
//			else
//			{
//				throw exception;
//			}
		}
		
	private:
		
		enum COLOR{BLACK,RED};
		
		struct RBTreeNode
		{
			COLOR color;					//結點顏色 
			Comparable data;				//結點數據 
			struct RBTreeNode* parent;	//父節點指針 
			struct RBTreeNode* lchild;	//左孩子結點指針 
			struct RBTreeNode* rchild;	//右孩子結點指針 
			
			RBTreeNode(): color(BLACK),data(Comparable()),
							parent(NULL),lchild(NULL),rchild(NULL){}
			RBTreeNode(const Comparable& elem ): color(BLACK),data(elem),
							parent(NULL),lchild(NULL),rchild(NULL){}
		};
		//========================================
		RBTreeNode * root;				//根結點 
		RBTreeNode * nil;				//哨兵結點 
		//========================================
		
		void leftRotate(RBTreeNode* x)	//左旋 
		{
			RBTreeNode* y = x->rchild;
			x->rchild = y->lchild;
			if(y->lchild != nil)
			{
				y->lchild->parent = x;
			}
			y->parent = x->parent;
			if(x->parent == nil)
			{
				root = y;				//y爲新的根結點 
			}
			else if(x == x->parent->lchild)
			{
				x->parent->lchild = y;
			}
			else
			{
				x->parent->rchild = y;
			}
			y->lchild = x;
			x->parent = y;
		}
		
		void rightRotate(RBTreeNode* x)//右旋 
		{
			RBTreeNode* y = x->lchild;
			x->lchild = y->rchild;
			if(y->rchild != nil)
			{
				y->rchild->parent = x;
			}
			y->parent = x->parent;
			if(x->parent == nil)
			{
				root = y;
			}
			else if(x == x->parent->lchild)
			{
				x->parent->lchild = y;
			}
			else
			{
				x->parent->rchild = y;
			}
			y->rchild = x;
			x->parent = y;
		}
		
		//插入之後的修復操作 
		void insertFixup(RBTreeNode* z)
		{ 
			RBTreeNode* y;				//y是z的叔父結點 
			while(z->parent->color == RED)	
			{
				//z的父結點是z的祖父結點的左孩子 
				if(z->parent == z->parent->parent->lchild)
				{
					//case 1 2 3
					y = z->parent->parent->rchild;
					if(y->color == RED)		
					{
						//case1 
						z->parent->color = BLACK;
						y->color = BLACK;
						z->parent->parent->color = RED;
						z = z->parent->parent;
					}
					else //case2 or case 3 ,y->color == BLACK
					{						
						//case2
						if(z == z->parent->rchild)
						{
							z = z->parent;		//z上溯至父節點 
							leftRotate(z);		//左旋
						}
						//case3
						z->parent->color = BLACK;
						z->parent->parent->color = RED;
						rightRotate(z->parent->parent);
					}							
				}
				else//case 4,5,6與上面對稱 
				{
					y = z->parent->parent->lchild;
					if(y->color == RED)
					{
						//case4
						z->parent->color = BLACK;
						y->color = BLACK;
						z = z->parent->parent;
					}
					else//case 5 or case 6
					{
						//case 5
						if(z == z->parent->lchild)
						{
							z = z->parent;
							rightRotate(z);
						}
						//case 6
						z->parent->color = BLACK;
						z->parent->parent->color = RED;
						leftRotate(z->parent->parent);
					}
				}
			}
			root->color = BLACK;
		}		
		
		//刪除之後的修復操作		
		void removeFixup(RBTreeNode* x)
		{
			RBTreeNode* w;			//x的兄弟結點 
			
			while(x != root && x->color == BLACK)
			{
				if(x == x->parent->lchild)//case1-4
				{
					w = x->parent->rchild;
					if(w->color == RED)
					{
						//case1
						w->color = BLACK;
						x->parent->color = RED;
						leftRotate(x->parent);
						w = x->parent->rchild;
					}
					
					//w->color == BLACK
					if(w->lchild->color == BLACK && w->rchild->color == BLACK)
					{
						//case 2
						w->color = RED;
						x = x->parent;//
					}
					else  
					{
						//case 3 
						if(w->rchild->color == BLACK)//左子爲RED
						{							
							w->lchild->color = BLACK;
							w->color = RED;
							rightRotate(w);
							w = x->parent->rchild;
						}
						//case 4 右子爲RED
						w->color = x->parent->color;
						x->parent->color = BLACK;
						w->rchild->color = BLACK;
						leftRotate(x->parent);
						x = root;
					}					
				}
				else//case5-8,和上面對稱 
				{
					w = x->parent->lchild;
					if(w->color == RED)
					{
						//case 5
						w->color = BLACK;
						x->parent->color = RED;
						rightRotate(x->parent);
						w = x->parent->lchild;
					}
					
					//w->color == BLACK
					if(w->lchild->color == BLACK && w->rchild->color == BLACK)
					{
						//case 6
						w->color = RED;
						x = x->parent;//
					}
					else  
					{
						//case 7
						if(w->lchild->color == BLACK)//右子爲RED
						{							
							w->rchild->color = BLACK;
							w->color = RED;
							leftRotate(w);
							w = x->parent->lchild;
						}
						//case 8 左子爲RED
						w->color = x->parent->color;
						x->parent->color = BLACK;
						w->lchild->color = BLACK;
						rightRotate(x->parent);
						x = root;
					}
				}
			}
			
			x->color = BLACK;
		}
		
		//在以t爲根的紅黑樹中查找給定元素
		//返回相應的結點指針 
		RBTreeNode* search(const Comparable& elem, RBTreeNode* t)const
		{
			while(t != nil && elem != t->data)
			{
				if(elem < t->data)
				{
					t = t->lchild;
				}
				else if(t->data < elem)
				{
					t = t->rchild;
				}
			}
			return t;
		}
		
		//求結點x的中序後繼結點 
		RBTreeNode* successor(RBTreeNode* x)
		{
			RBTreeNode* y;
			
			if(x->rchild != nil)
			{
				y = x->rchild;
				while(y->lchild != nil)
				{
					y = y->lchild;
				}
			}
			else
			{
				y = x->parent;
				while(y != nil && x == y->rchild)
				{
					x = y;
					y = y->parent;
				}
			}
			return y;
		}
		
		//前序遍歷 
		void preOrderTraverse(RBTreeNode* t)const
		{
			if(t != nil)
			{
				cout<<"("<<t->data<<",";
				t->color ?  cout<<"RED" : cout<<"BLACK";
				cout<<")";
				preOrderTraverse(t->lchild);
				preOrderTraverse(t->rchild);
			}
		}
		
		//中序遍歷 
		void inOrderTraverse(RBTreeNode* t)const
		{
			if(t != nil)
			{				
				inOrderTraverse(t->lchild);
				cout<<"("<<t->data<<",";
				t->color ?  cout<<"RED" : cout<<"BLACK";
				cout<<")";
				inOrderTraverse(t->rchild);
			}
		}
		
		//銷燬紅黑樹 
		void makeEmpty(RBTreeNode* t)
		{
			if(t != nil)
			{
				makeEmpty(t->lchild);
				makeEmpty(t->rchild);
				delete t;
				t = NULL;
			}
		}
};

int main(int argc, char *argv[])
{
	RBTree<int> rbtree;
	const int N = 6;
	//insert
	for(int i=1; i<N;i++)
	{
		rbtree.insert(i);
		cout<<"after insert "<<i<<":"<<endl;
		rbtree.printTree();
	}
	
	//search
	cout<<"search: "<<endl;
	for(int i=1; i<N;i++)
	{
		cout<<"("<<i<<","<<rbtree.search(i)<<")";
	}
	cout<<endl<<endl;
	
	//remove	
	for(int i=1; i<N; i += 2)
	{
		rbtree.remove(i);
		cout<<"after remove: "<<i<<endl;
		rbtree.printTree();
	}

	//search
	cout<<"search: "<<endl;	
	for(int i=1; i<N;i++)
	{
		cout<<"("<<i<<","<<rbtree.search(i)<<")";
	}
	cout<<endl<<endl;
	
    system("PAUSE");
    return EXIT_SUCCESS;
}

參考資料:

[1]算法導論(第2版)第13章P163-P176

[2]紅黑樹及擴張:http://wenku.baidu.com/view/673d3e6eb84ae45c3b358c29.html

[3]博客文章(C#實現):http://www.cnblogs.com/abatei/archive/2008/12/17/1356565.html

[4]Data Structures and Algorithm Analysis in C++(third editon) (數據結構與算法分析C++描述,第3版 )

[5]文章(C++實現):http://www.linuxidc.com/Linux/2012-01/52530.htm

[6]文章(C實現):http://www.chinaunix.net/old_jh/23/1308846.html

[7]C語言實現:http://wenku.baidu.com/view/1187190390c69ec3d5bb7544.html

[8]紅黑樹的實現與討論:http://www.cppblog.com/daly88/archive/2009/11/20/101519.html

發佈了38 篇原創文章 · 獲贊 10 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章