紅黑樹
上一篇中講到,一棵高度爲h的二叉搜索樹,它所進行的操作都可以在O(h)時間內完成。因此搜索樹的高度較低時,可以較快的完成。但是,如果樹的高度較高時,這些集合操作可能並不比鏈表上快。如何實現一種搜索樹的結構,使得其任何一種基本操作都可以在O(lgn)的時間內完成呢?
紅黑樹,就是這種“平衡”搜索樹中的一種。可以保證最壞的情況下,基於動態集合操作的時間複雜度爲O(lgn)。
紅黑樹,也是一種二叉搜索樹,也支持search, predecessor, successor, minimum, maximum, insert 和 delete等操作,但是卻有着和普通二叉搜索樹不同的性質,於是也導致它的某些操作的複雜性,但是以code的複雜度換取時間的複雜度,不亦樂乎。
下面開始一起走入紅黑樹吧:
1、性質:
(1)每個結點要麼是紅色,要麼是黑色;
(2)根結點是黑色的;
(3)每個葉子結點是黑色的。
(4)如果一個結點是紅色的,則它的兩個子結點都是黑色的。
(5)對於每個結點,從該結點到其所有後代葉結點的簡單路徑上,均包含相同數目的黑色結點。
Left_Rotate( T, x)
y = x.right
x.right = y.left
if y.left != T.NIL
y.left.p = x
y.p = x.p
if x.p = T.NIL
T.root = y
else if x = x.p.left
x.p.left = y
else
x.p.right = y
y.left = x
x.p = y
// RB_Tree_.cpp : 定義控制檯應用程序的入口點。
//
#include "stdafx.h"
#include <iostream>
using namespace std;
enum Color
{
Black,
Red
};
typedef struct RB_Node
{
Color color;
int key;
struct RB_Node *left;
struct RB_Node *right;
struct RB_Node *p;
}RB_Node, *p_RB_Node;
RB_Node *T_NULL = NULL;
RB_Node * FindNode(RB_Node *root, int k)
{
while(root!=NULL && k!=root->key)
{
if(k<root->key)
root = root->left;
else
root = root->right;
}
if(root == NULL)
return NULL;
else
return root;
}
RB_Node * RB_Tree_Minimum(RB_Node *x)
{
RB_Node *y = T_NULL;
while(x!=T_NULL)
{
y = x;
x = x->left;
}
return y;
}
RB_Node * Succssor(RB_Node *root, RB_Node *x)
{
if(x->right !=T_NULL)
return RB_Tree_Minimum(x->right);
RB_Node *y = x->p;
while(y!=T_NULL && x == y->right)
{
x = y;
y = y->p;
}
return y;
}
void Left_Rotate(p_RB_Node *root, RB_Node *x)
{
RB_Node *y = x->right;
x->right = y->left;
if(y->left!=T_NULL)
y->left->p = x;
y->p = x->p;
if(x->p == T_NULL)
*root = y;
if(x == x->p->left)
x->p->left = y;
else
x->p->right = y;
y->left = x;
x->p = y;
}
void Right_Rotate(p_RB_Node *root, RB_Node *x)
{
RB_Node *y = x->left;
x->left = y->right;
if(y->right != T_NULL)
y->right->p = x;
y->p = x->p;
if(x->p ==T_NULL)
*root = y;
if(x == x->p->left)
x->p->left = y;
else
x->p->right = y;
y->right = x;
x->p = y;
}
void RB_Insert_FixUP(p_RB_Node *root, RB_Node *z)
{
/*
1.z是要插入的節點,p是其父節點,G是祖父節點,W是叔父節點;存在兩種情況:p = G.left and p = G.right
注意破壞的是什麼性質,去fix的是什麼性質。
*/
while(z->p->color == Red)
{
RB_Node *p = z->p;
RB_Node *G = z->p->p;
RB_Node *W = T_NULL;
if(p == G->left)
{
W = G->right;
//case 1:z的父節點p和叔父節點W均是紅色,那麼G一定是黑色,則將p和w均着爲黑色,將G着爲紅色
if( W->color ==Red)
{
p->color = Black;
W->color = Black;
G->color = Red;
z = G;
}
//case 2:w是黑色,且z是其父節點的右孩子,那麼將p作爲當前節點,並以它爲支點,左旋
else if(z == p->right)
{
z = p;
Left_Rotate(root,p);
}
//case 3:w是黑色,z是p的左孩子,將p,G的顏色交換,然後以G爲支點,右旋。
else
{
p->color = Black;
G->color = Red;
Right_Rotate(root,G);
}
}
else
{
W = G->left;
if( W->color ==Red)
{
p->color = Black;
W->color = Black;
G->color = Red;
z = G;
}
else if(z == p->left)
{
z = p;
Right_Rotate(root,p);
}
else
{
p->color = Black;
G->color = Black;
Left_Rotate(root,G);
}
}
}
(*root)->color = Black;
}
void RB_Insert(p_RB_Node *root, int k)
{
RB_Node *x = *root;
RB_Node *z = new RB_Node;
RB_Node *temp = T_NULL;
z->color = Red;
z->key = k;
z->left = z->right = z->p = T_NULL;
while(x!=T_NULL)
{
temp = x;
if(k<x->key)
x = x->left;
else
x = x->right;
}
z->p = temp;
if(temp == T_NULL)
*root = z;
else if(k<temp->key)
z->p->left = z;
else
z->p->right = z;
if(z->p==T_NULL)
z->color = Black;
else
RB_Insert_FixUP(root,z);
//delete z;
}
void RB_Delete_Fixup(p_RB_Node *root, RB_Node *x)
{
while(x!=(*root)&& x->color != Red)
{
RB_Node *p = x->p;
RB_Node *w = T_NULL; //w爲x的兄弟節點
if(x == p->left)
{
w = p->right;
//case 1: 兄弟w 爲紅色,那麼p一定是黑色,p與w換顏色,然後以p 爲支點左旋
if(w->color == Red)
{
w->color = Black;
p->color = Red;
Left_Rotate(root,p);
}
//case 2: 兄弟爲黑色,且兄弟的兩孩子也均爲黑色,分別提取x和w的一層黑,加到p上,以p作爲新的x 結點,繼續遞歸
if(w->left->color == Black && w->right->color == Black)
{
w->color = Red;
p->color = Black;
x = p;
}
//case 3:兄弟爲黑色,左孩子爲紅色,右孩子爲黑色。
//w與w.left交換顏色,然後以w爲支點右旋---->到達case 4
else if(w->left->color == Red && w->right->color == Black)
{
w->left->color = Black;
w->color = Red;
Right_Rotate(root,w);
}
//case 4:兄弟爲黑色,右孩子爲紅色,左孩子任意。
//w着爲p的顏色,p着爲黑色,兄弟右子結點染黑。然後以p爲支點左旋,最終恢復紅黑樹的性質
else if(w->right->color == Red)
{
w->color = p->color;
p->color = Black;
w->right->color = Black;
Left_Rotate(root,p);
x =(*root);
}
}
else
{
w = p->left;
if(w->color == Red)
{
w->color = Black;
p->color = Red;
Right_Rotate(root,p);
}
if(w->left->color == Black && w->right->color == Black)
{
w->color = Red;
p->color = Black;
x = p;
}
else if(w->right->color == Red && w->left->color == Black)
{
w->right->color = Black;
w->color = Red;
Left_Rotate(root,w);
}
else if(w->left->color == Red)
{
w->color = p->color;
p->color = Black;
w->left->color = Black;
Right_Rotate(root,p);
x = (*root);
}
}
}
(*root)->color = Black;
}
void RB_Delete_Node(p_RB_Node *root, int k)
{
//z是要刪除的節點,y是實際上被刪除的節點,x是y節點的孩子
RB_Node *z = FindNode(*root,k);
RB_Node *y = T_NULL;
RB_Node *x = T_NULL;
if(z->left == T_NULL && z->right == T_NULL)
y = z;
else
y = Succssor(*root,z);
if(y->left !=T_NULL)
x = y->left;
else
x = y->right;
x->p = y->p;
if(x->p == T_NULL)
*root = x;
else if(y == y->p->left)
y->p->left = x;
else
y->p->right = x;
if(y!=z)
z->key = y->key;
if(y->color == Black)
RB_Delete_Fixup(root,x);
}
void RB_Tree_Inoder(RB_Node *root)
{
if(root!=T_NULL)
{
RB_Tree_Inoder(root->left);
printf("%d ,",root->key);
RB_Tree_Inoder(root->right);
}
}
void RB_Tree_Create(p_RB_Node *root)
{
int a[] = {12,1,9,2,0,11,7,19,4,15,18,5,14,13,10,16,6,3,8,17};
for(int i = 0;i<20;i++)
{
RB_Insert(root,a[i]);
}
}
int _tmain(int argc, _TCHAR* argv[])
{
T_NULL = new RB_Node;
T_NULL->color = Black;
T_NULL->left = NULL;
T_NULL->right = NULL;
T_NULL->p = NULL;
T_NULL->key = 0;
RB_Node *root = T_NULL;
RB_Tree_Create(&root);
RB_Tree_Inoder(root);
cout<<endl;
RB_Delete_Node(&root,12);
RB_Tree_Inoder(root);
cout<<endl;
RB_Delete_Node(&root,1);
RB_Tree_Inoder(root);
cout<<endl;
RB_Delete_Node(&root,9);
RB_Tree_Inoder(root);
cout<<endl;
return 0;
}