// 数据结构_红黑树.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
/*红黑树
我们知道一颗高度为h的二叉查找树,可以实现任何一种基本的动态集合操作
其时间都是 O(h),当树的高度很低时,这些操作会很快,但当树的高度很高时,这些操作可能可能不比链表好
红黑树是许多平衡的查找树的一种,它能保证在最坏的情况下,基本的动态集合的操作时间为O(lgn)
树中每个结点都包含五个域:color,key,left,right,p.我们把指向NIL的指针视为指向外结点的指针,而把关键字的结点视为内结点
一颗二叉查找树如果满足下面的红黑性质,则为一颗红黑树
1) 每个结点或是红的,或是黑的
2)根结点是黑的
3) 每个叶结点(NIL)都是黑的
4)如果一个结点是红的,则它的两个儿子都是黑的
5)对每个结点,从该结点到其子孙结点的所有路径上包含相同数目的黑结点
从某个结点x出发(不包含该结点)到达一个叶结点的任意的一条路径上,黑色结点的个数称为该结点x的黑高度
红黑树的黑高度,定义为其根结点的黑高度*/
enum COLOR{
RED,
BLACK
};
typedef struct RBTREE{
RBTREE *left;
RBTREE *right;
RBTREE *p;
int key;
COLOR color;
}RBTREE,*PRBTREE;
PRBTREE nil,root;
RBTREE *tree_minimum(RBTREE *x){
while(nil != x->left){
x = x->left;
}
return x;
}
RBTREE *tree_successor(RBTREE *x){
PRBTREE y = NULL;
if(x->right != nil){
return tree_minimum(x->right);// x 的右子树的最左孩子就是x的后继
}
y = x->p;// x结点没有右子树,如果x是其父结点的左孩子,直接返回x的父结点
while((y != nil) &&(x == y->right)){//如果x结点,是其父结点的右孩子,一直要找一个,其父结点是要找结点的左孩子。返回这个结点
x = y;
y = y->p;
}
return y;
}
/*旋转
当在含有n个关键字的红黑树上运行时,查找和删除,可能违反红黑树的性质,为保持这些性质
就要改变树中某些结点的颜色以及指针结构
指针结构的修改是通过旋转来完成的,这是一种能保持二叉查找树性质的查找树局部操作,有两种旋转,左旋和右旋
当在某个结点x上做左旋转时,我们假设它的右孩子y不是nil[T],x可以为树内任意右孩子不是nil[T]的结点,左旋以
x到y之间的链为支轴进行,它使y成为该子树新的根,x成为y的左孩子,y的左孩子成为x的右孩子
*/
/*
LEFT-ROTATE(T,x)
1 y <- left[x]
2 right[x] = left[y]
3 if left[y] != nil[T]
4 then p[left[y]] <- x
5 p[y] <- p[x]
6 if p[x] = nil[T]
7 then root[T] <- y
8 else if x = left[p[x]]
9 then left[p[x]] <- y
10 else right[p[x]] <- y
11 left[y] <- x
12 p[x] <- y
*/
int left_rotate(RBTREE *x){
PRBTREE y;
y = x->right;
x->right = y->left;
if (nil != y->left){
y->left->p = x;
}
y->p = x->p;
if(nil == x->p){
root = y;
}else if(x == x->p->left){
x->p->left = y;
}
else{
x->p->right = y;
}
y->left = x;
x->p = y;
return 0;
}
/*
RIGHT-ROTATE(T,x)
1 y <- right[x]
2 left[x] = right[y]
3 if right[y] != nil[T]
4 then p[right[y]] <- x
5 p[y] <- p[x]
6 if p[x] = nil[T]
7 then root[T] <- y
8 else if x = right[p[x]]
9 then right[p[x]] <- y
10 else left[p[x]] <- y
11 right[y] <- x
12 p[x] <- y
*/
int right_rotate(RBTREE *x){
PRBTREE y;
y = x->left;
x->left = y->right;
if (nil != y->right){
y->right->p = x;
}
y->p = x->p;
if(nil == x->p){
root = y;
}else if(x == x->p->right){
x->p->right = y;
}
else{
x->p->left = y;
}
y->right = x;
x->p = y;
return 0;
}
/*
RB-INSERT-FIXUP(T,z)
1 while color[p[z]] = RED
2 do if p[z] = left[p[p[z]]]
3 then y <- right[p[p[z]]]
4 if color[y] = RED
5 then color[p[z]] <- BLACK Case 1
6 color[y] <- BLACK Case 1
7 color[p[p[y]]] <- RED Case 1
8 z <- p[p[z]] Case 1
9 else if z = right[p[z]]
10 then z <- p[z] Case 2
11 LEFT_ROTATE(T,z) Case 2
12 color[p[z]] <- BLACK Case 3
13 color[p[p[z]]] <- RED Case 3
14 RIGHT-ROTATE(T,p[p[z]]) Case 3
15 else (same as the clause with "right" and "left" exchanged)
16 color[root[T]] <- BLACK
*/
int rb_insert_fixup(RBTREE *z){
PRBTREE y = NULL;
while(RED == z->p->color){
if(z->p == z->p->p->left){
y = z->p->p->right;
if(RED == y->color){
z->p->color = BLACK;
y->color = BLACK;
z->p->p->color = RED;
z = z->p->p;
}
else if(z == z->p->right){
z = z->p;
left_rotate(z);
}
else{
z->p->color = BLACK;
z->p->p->color = RED;
right_rotate(z->p->p);
}
}
else{
y = z->p->p->left;
if(RED == y->color){
z->p->color = BLACK;
y->color = BLACK;
z->p->p->color = RED;
z = z->p->p;
}
else if(z == z->p->left){
z = z->p;
right_rotate(z);
}
else{
z->p->color = BLACK;
z->p->p->color = RED;
left_rotate(z->p->p);
}
}
}
root->color = BLACK;
return 0;
}
/*
插入
RB-INSERT(T,z)
1 y <- nil[T]
2 x <- root[T]
3 while x != nil[T]
4 do y <- x
5 if key[z] < key[x]
6 then x <- left[x]
7 else x <- right[x]
8 p[z] <- y
9 if y = nil[T]
10 then root[T] <- z
11 else if key[z] < key[y]
12 then left[y] <- z
13 else right[y] <- z
14 left[z] <- nil[T]
15 right[z] <- nil[T]
16 color[z] <- RED
17 RB-INSERT-FIXUP(T,z)
*/
int rb_insert(RBTREE *z){
PRBTREE y = NULL,x = NULL;
y = nil;
x = root;
while(nil != x){
y = x;
//根据二叉排序树的性质,左边子树小于根结点,右边子树大于根结点,找到z的父亲
if(z->key < x->key){
x = x->left;
}
else{
x = x->right;
}
}
//设置z的父结点
z->p = y;
//当我们第一次插入根结点时,y等于nil,直接将root设置成z.
if(nil == y){
root = z;
}
//设置z的父亲的孩子结点
else if(z->key < y->key){
y->left = z;
}
else{
y->right = z;
}
//设置待插入结点的左右孩子,color域
z->left = nil;
z->right = nil;
z->color = RED;
//结点的插入完毕,进行红黑树性质的保持。
rb_insert_fixup(z);
return 0;
}
/*和n个结点的红黑树上的其他操作基本操作一样,对一个结点的删除要花O(lg n)的时间 */
/*
RB-DELETE(T,z)
1 if left[z] = nil[T] or right[z] = nil[T]
2 then y <- z
3 else y <- TREE-SUCCESSOR(z)
4 if left[y] != nil[T]
5 then x <- left[y]
6 else x <- right[y]
7 p[x] <- p[y]
8 if p[y] = nil[T]
9 then root[T] <- x
10 else if y = left[p[y]]
11 then left[p[y]] <- x
12 else right[p[y]] <- x
13 if y != x
14 then key[z] <- key[y]
15 copy y's statlite data into z
16 if color[y] = BLACK
17 then RB-DELETE-FIXUP(T,x)
18 return y
过程TREE-DELETE和RB-DELETE之间有三点不同,首先,TREE-DELETE中所有对NIL的引用在RB-DELETE中都被替换成对哨兵nil[T]的引用
其次,TREE-DELETE的第七行中的判断x是否为NIL的测试被去掉了,取而代之,无条件执行p[x] <- p[y],这样,如果x是哨兵nil[T],其父指针就指向被删除的结点y的父亲。第三
在第16,17行如果y是黑色的,则调用RB-DELETE-FIXUP,如果y是红色的,则当y被删除后,红黑性质得以保持,理由如下:
树中的各结点的黑高度没有变化
不存在相邻的红色结点
如果y是红色的,就不可能是根,所以根仍然是黑色的。
*/
int rb_delete_fixup(RBTREE *x);
RBTREE *rb_delete(RBTREE *z){
PRBTREE y = NULL,x = NULL;
//如果待删除的结点是叶子结点,或者只有一个孩子
if(( z->left == nil)||(z->right == nil)){
y = z;
}
else{
//如果待删除的结点有两个孩子,y此时等于z的后继
y = tree_successor(z);
}
//x等于z的孩子,对于z有两个孩子的情况,x等于nil。
if(y->left != nil){
x = y->left;
}
else{
x = y->right;
}
//因为要删除z所以,将z的孩子的父亲设置为z的父亲。
x ->p = y->p;
if(y->p == nil){
root = x;
}
//设置待删除的z的父亲的左右孩子指针。如果是两个孩子的情况,将其后继的的父亲的孩子设置为nil.
else if(y = y ->p->left){
y->p->left = x;
}
else{
y->p->right = x;
}
if(y != x){
z->key = y->key; // 拷贝后继的值到z中。
}
if(y->color == BLACK){
rb_delete_fixup(x);
}
return y;
}
/*
传递给RB-DELETE-FIXUP的结点x是两个结点中的一个,在y被删除之前,如果y有个不是哨兵nil[T]的孩子,则x为y的唯一孩子,如果y没有孩子,则x为哨兵nil[T].第7行中的无条件赋值保证
无论x是有关键字的内结点或哨兵nil[T],x现在的父结点都为先前y的父结点
RB-DELETE-FIXUP(T,x)
1 while x != root[T] and color[x] = BLACK
2 do if x = left[p[x]]
3 then w <- right[p[x]]
4 if color[w] = RED
5 then color[w] <- BLACK Case 1
6 color[p[x]] <- RED Case 1
7 LEFT-ROTATE(T,p[x]) Case 1
8 w <- right[p[x]] Case 1
9 if color[left[w]] = BLACK and color[right[w]] = BLACK
10 then color[w] <- RED Case 2
11 x <- p[x] Case 2
12 else if color[right[w]] = BLACK
13 then color[left[w]] <- BLACK Case 3
14 color[w] <- RED Case 3
15 RIGHT-ROTATE(T,w) Case 3
16 w <- right[p[x]] Case 3
17 color[w] <- color[p[x]] Case 4
18 color[p[x]] <- BLACK Case 4
19 color[right[w]] <- BLACK Case 4
20 LEFT-ROTATE(T,p[x]) Case 4
21 x <- root[T] Case 4
22 else (same as then clause with "right" and "left" exchanged)
23 color[x] <- BLACK
*/
int rb_delete_fixup(RBTREE *x){
PRBTREE w = NULL;
while((x != root)&&(x->color == BLACK)){
if(x == x->p->left){ //如果x是其父亲的左孩子
w = x->p->right; //w是x的兄弟。
if(w->color == RED){ //如果x的兄弟是红色的。
w->color = BLACK;
x->p->color = RED;
left_rotate(x->p);
w = x->p->right;//将情况转换为2,3,4情况
if((w->left->color == BLACK)&&(w->right->color == BLACK)){//如果w的左右孩子都是BLACK的,将w的颜色设置为RED.
w->color = RED;
x = x->p;
}
else if(w->right->color == BLACK){ //如果W的右孩子颜色为BLACK.
w->left->color = BLACK; // 将w的左孩子的颜色设置为BLACK,并把w的颜色设置为RED.
w->color = RED;
right_rotate(w);
w = x->p->right;
}
}
else{
w->color = x->p->color;
x->p->color = BLACK;
w->right->color = BLACK;
left_rotate(x->p);
x = root;
}
}
else{
w = x->p->left;
if(w->color == RED){
w->color = BLACK;
x->p->color = RED;
right_rotate(x->p);
w = x->p->left;
if((w->right->color == BLACK)&&(w->left->color == BLACK)){
w->color = RED;
x = x->p;
}
else if(w->left->color == BLACK){
w->right->color = BLACK;
w->color = RED;
left_rotate(w);
w = x->p->left;
}
}
else{
w->color = x->p->color;
x->p->color = BLACK;
w->left->color = BLACK;
right_rotate(x->p);
x = root;
}
}
x ->color = BLACK;
}
return 0;
}
int main(int argc, char* argv[])
{
int a[] = {2,3,7,4,6,14,12,9,11,22,20,17,19,18};
int i = 0;
PRBTREE ptemp = NULL;
nil = (RBTREE *)malloc(sizeof(PRBTREE));
nil->color = BLACK;
root = (RBTREE *)malloc(sizeof(PRBTREE));
root->left = nil;
root->right = nil;
root->p = nil;
root = nil;
for(i = 0;i < 14;i++){
ptemp = (RBTREE *)malloc(sizeof(PRBTREE));
ptemp->key = a[i];
ptemp->left = nil;
ptemp->right = nil;
ptemp->p = nil;
rb_insert(ptemp);
}
rb_delete(root->right->left);
return 0;
}