前面我們講解了簡單二叉查找樹、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