目标:实现13-1的思考题,要求是使用红黑树进行插入和删除的维护,同时要求这个数据结构是具有full persistence性质(可以对任意时刻的数据结构进行操作,产生多个分支),相关数据结构的操作为插入insert,删除delete两个。
persistent data structures,持久数据结构。其特点是保存了数据结构在某些操作前后的状态。持久数据结构属于temporal data structures 的一种。
最简单的办法是每一次操作都去复制整个树的所有节点。不过13-1给我们提供了一个更好的解决办法,通过发掘每一次操作后数据结构的共性来减少某一操作所带来的消耗。
这里还需要发掘这种方法能带来多少收益。
对于具有红黑树性质的持久二叉搜索树的插入操作来说,插入一个元素会改变插入元素的父节点的左或者右节点的元素域,为了不去损坏插入前的搜索树,那么这就意味着这次插入节点x的父节点xp需要被复制出来,成为一个新的节点。这时候会发现一旦xp节点需要改变那么就会产生连锁效应,视数据结构而定有两点问题:
1.插入节点x的父节点xp的父节点xpp的孩子xp只能有一个,现在xp节点被复制产生了xp1节点,又xp1节点负责x节点的插入,而原来的xp节点所有成员不变。那么对于xpp 节点而言,它的孩子本身是xp,为了不让xp1节点悬空,只能在复制xpp节点,产生xpp1节点指向xp1节点。以此类推产生连锁效应,至少从插入节点位置到根节点都要进行复制。故而有了书上的示意图:
此图中插入节点为5,5的父节点xp1 为阴影7节点,xp为7无阴影节点,xpp为8无阴影节点,xpp1为8阴影节点。
2. 第二个问题根据具体数据结构而产生,如果节点中保护parent域,那么还会产生更多的连锁效应,当xp产生复制节点xp1的时候,x如果原来存在兄弟节点xb,那么x的兄弟节点xb原来的parent的域是指向xp的,现在新的树种xp1节点的另一个孩子如果还指向xb的话,那么xb的parent域有不能只想xp1,导致数据结构中的父子关系被破坏,所以xb节点就也要产生一个新的节点xb1,与xp1形成父子关系,以此类推,由于从跟节点到x节点的路径上所有节点都会被复制,那么这些节点的兄弟节点就也会被复制,造成插入的工作时间为O(n),这就回答了思考题中的d,第四个问题。
有着两点可以看出,不去维护红黑树性质并且也不带父节点的持久二叉搜索树的插入性能为O(log n),空间代价也为O(log n)。那么维护红黑树性质又需要多少时间和空间呢?
先来看红黑树插入的维护过程,x被插入后因为是红节点,有可能破坏了新产生的树Tree1的红黑树基本性质4,这时候插入的修复会去改变节点z,和parent,parent->parent,z的兄弟z-brother的颜色或者左右孩子关系。这四个节点在每一次rb-insert-fixup里面的循环中都有可能会被改变,那么就应该去复制这四个节点,而不论在循环的任意时刻z和parent,parent-parent都是已经复制过的节点,那么我们只需要再次复制z的兄弟节点即可。这样整个插入过程的时间消耗为log(n)+log(n),空间消耗为2*log(n)。
使用c来实现,数据结构为
typedef struct node{
struct node *left;
struct node *right;
int color;
int data;
int size;
} *RBT;
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#include <time.h>
#define BLACK 1
#define RED 0
#define RBT_NODE RBT
#define ROOT(T) (T->left)
typedef struct node{
struct node *left;
struct node *right;
struct node *parent;
int color;
int data;
int size;
} *RBT;
#define RBTREE_INIT(name) {0,0, 0,BLACK,0,0}
#define NODE_INIT(name) {0,0,0,RED,0,0};
static RBT_NODE garbage[500];
static int garbageSize = 0;
static RBT_NODE trace[64];
static int trace_size;
void deleteAll()
{
for(int i = 0;i<garbageSize;++i)
free(garbage[i]);
}
static int valid;
int black_hight;
int check(RBT T,RBT_NODE n,int level)
{
if(n == T->left&&level != 1){
puts("leaf node problem:n == T->left&&trace_size != 1");
return 0;
}
if(n==0){
int t = 0;
//trace[trace_size] = n;
for(int i = 1;i<level;++i){
if(trace[i]->color == BLACK){
t++;
}
}
if(valid)
{
if(black_hight != t){puts("black_hight not eq");return 0;}
}else{
valid = 1;
black_hight = t;
}
}else{
trace[level] = n;
if(n->color == RED){
if(n->left==0&&n->right!=0){
puts("red node not followd black node 1");
return 0;
}else if(n->left!=0&&n->right==0){
puts("red node not followd black node 2");
return 0;
}else if(n->left!=0&&n->left->color!=BLACK||n->right!=0 &&n->right->color!=BLACK){
puts("red node not followd black node 3");
return 0;
}
}
if(!check(T,n->left,level+1)){
return 0;
}
if(!check(T,n->right,level+1)){
return 0;
}
}
return 1;
}
RBT_NODE new_node(RBT_NODE in)
{
if(in == 0) return in;
RBT_NODE y = (RBT_NODE)malloc(sizeof(struct node));
//garbage[garbageSize++] = y;
garbageSize++;
//if(garbageSize%100 == 0)
// printf("garbageSize = %d\n",garbageSize);
y->left = in->left;
y->right = in->right;
y->data = in->data;
y->color = in->color;
y->size = in->size;
}
RBT_NODE copy_node(RBT_NODE in,RBT_NODE parent)
{
RBT_NODE temp = new_node(in);
if(in == parent->left){
parent->left = temp;
}else{
parent->right = temp;
}
return temp;
}
void left_rotate(RBT T,RBT_NODE x)
{
/*
旋转分析:完成树的分支的旋转,并维护树的本身特性。
不改变trace栈。
进入条件trace栈顶存储着x的父亲。
*/
//puts("left_rotate in");
if(x == 0||trace[trace_size-1]->left != x&&trace[trace_size-1]->right!=x){puts("error left_rotate ");}
//x != Null
RBT_NODE parent = trace[trace_size - 1];
//parent为x的父母,x!=Null
struct node * y = x->right;
//parent为x的父母,x!=Null,y等于x->right
if(y == 0) return ;
//parent为x的父母,x!=Null,y等于x->right且y不为空。
x->right = y->left;
//
int temp = y->size;
y->size = x->size;
x->size-=temp;
if(y->left != 0){
x->size += y->left->size;
}
y->left = x;
if(x == parent->left){
parent->left = y;
}else{
parent->right = y;
}
//puts("left_rotate out");
}
void right_rotate(RBT T,RBT_NODE x)
{
//puts("right_rotate in");
if(x == 0||trace[trace_size-1]->left != x&&trace[trace_size-1]->right!=x)
{puts("error right_rotate ");}
RBT_NODE parent = trace[trace_size - 1];
struct node *y = x->left;
if(y == 0) return ;
x->left = y->right;
int temp = y->size;
y->size = x->size;
x->size -= temp;
if(x->left != 0){
x->size += x->left->size;
}
y->right = x;
if(parent->left == x){
parent->left = y;
}else{
parent->right = y;
}
//puts("right_rotate out");
}
void rb_insert_fixup(RBT T,RBT_NODE z)
{
//printf("T->left->data = %d\n",T->left->data);
RBT_NODE y;
RBT_NODE temp;
RBT_NODE parent = trace[--trace_size];
while(parent->color == RED)
{
RBT_NODE pparent = trace[trace_size-1];
if(parent == pparent->left){
y = pparent->right;
if(y!=0&&y->color == RED){
//因为这里要去改变y的颜色所以也不能和一前公用节点,
//不然会破坏原来的树
parent->color = BLACK;
temp = new_node(y);
pparent->right = temp;
z = pparent;
pparent->color = RED;
temp->color = BLACK;
trace_size--;
}else{
if(z == parent->right){
RBT_NODE temp = z;
z = parent;
left_rotate(T,z);
parent = temp;
}
parent->color = BLACK;
pparent-> color = RED;
trace_size --;
right_rotate(T,pparent);
break;
}
}else{
y = pparent->left;
if(y!=0&&y->color ==RED){
parent->color = BLACK;
z = pparent;
pparent->color = RED;
temp = new_node(y);
pparent->left = temp;
temp->color = BLACK;
trace_size--;
}else{
if(z == parent->left){
RBT_NODE temp = z;
z = parent;
right_rotate(T,z);
parent = temp;
}
parent->color = BLACK;
pparent->color = RED;
trace_size --;
left_rotate(T,pparent);
break;
}
}
parent = trace[--trace_size];
}
T->left->color = BLACK;
}
RBT rb_insert(RBT T,RBT_NODE z)
{
RBT temp,newT = new_node(T);
trace_size = 1;
trace[0] = newT;
newT->size++;
RBT_NODE y = newT;
RBT_NODE x = newT->left;
while(x != 0)
{
temp = new_node(x);
temp->size++;
trace[trace_size] = temp;
trace_size++;
if(x == y->left){
y->left = temp;
}else{
y->right = temp;
}
y = temp;
if(z->data < x->data)
{
x = x->left;
}else{
x = x->right;
}
}
if(y == newT){
newT->left = z;
}else if(z->data < y->data){
y->left = z;
}else{
y->right = z;
}
z->left = 0;
z->right = 0;
z->color= RED;
z->size = 1;
//printf("i am fine");
rb_insert_fixup(newT,z);
return newT;
}
void rb_transplant(RBT_NODE u,RBT_NODE v)
{
RBT_NODE parent = trace[trace_size-1];
if(u==parent->left){
parent->left = v;
}else parent->right = v;
//v->parent = u->parent;
//copy_node(v,u);
//free(v);
}
RBT_NODE tree_minimum(RBT T,RBT_NODE x)
{
RBT_NODE p = x;
while(p->left != 0){
trace[trace_size++] = p;
p = p->left;
}
return p;
}
void rb_delete_fixup(RBT T,RBT_NODE x)
{
RBT_NODE w,parent;
//当x不为跟节点,且x的颜色为黑或者x为空节点时候
while(x != T->left && (x==0 || x->color == BLACK))
{
//parent始终为x父亲,trace中始终为parent的祖先节点
// w始终跟踪x的兄弟
parent = trace[--trace_size];
if( x == parent->left)
{
w = parent->right;
w = copy_node(w,parent);
if(w->color == RED){
if(w->left == 0 ||w->right == 0)
puts("total wrong w->left == 0 ||w->right == 0 in rb_delete_fixup 1");
w->color = BLACK;
parent->color = RED;
left_rotate(T,parent);
trace[trace_size++] = w;
w = parent->right;
if(w == 0){
puts("error here");
}
w = copy_node(w,parent);
}
//现在w的颜色必为黑色,且w不为空节点。
if((w->left == 0 || w->left->color == BLACK) &&(w->right == 0|| w->right->color ==BLACK))
{
w->color = RED;
x = parent;
}else {
if(w->right == 0 || w->right->color == BLACK){
//if(w->left != 0){
w->left = copy_node(w->left,w);
w->left->color = BLACK;
//}
w->color = RED;
trace[trace_size++] = parent;
right_rotate(T,w);
trace_size--;
w = parent->right;
}
w->color = parent->color;
parent->color = BLACK;
if(w->right->color != RED){
puts("something wrong");
}
w->right = copy_node(w->right,w);
w->right->color = BLACK;
left_rotate(T,parent);
x = T->left;
}
}else{
w = parent->left;
w = copy_node(w,parent);
if(w->color == RED)
{
if(w->left == 0 ||w->right == 0)
puts("total wrong w->left == 0 ||w->right == 0 in rb_delete_fixup 2");
w->color = BLACK;
parent->color =RED;
right_rotate(T,parent);
trace[trace_size++] = w;
w = parent->left;
if(w == 0){
puts("error here");
}
w = copy_node(w,parent);
}
if((w->left == 0 || w->left->color == BLACK) && (w->right == 0|| w->right->color ==BLACK)){
//x->parent->color = BLACK;
w->color = RED;
x = parent;
}else{
if(w->left == 0 || w->left->color == BLACK){
w->right =copy_node(w->right,w);
w->right->color = BLACK;
w->color = RED;
trace[trace_size++] = parent;
left_rotate(T,w);
trace_size--;
w = parent->left;
}
w->color = parent->color;
parent->color = BLACK;
w->left = copy_node(w->left,w);
w->left->color = BLACK;
right_rotate(T,parent);
x = T->left;
}
}
}
if(x != 0)
x->color = BLACK;
}
int search_node(RBT_NODE root,RBT_NODE z,int level)
{
/*
关于search——node的有效性证明,root代表整个树的根节点,z代表需要搜索的节点,level代表当前搜索的root节点的深度
并把结果存储在全局栈root中。
对于当前搜索的深度level而言,trace中level以前的所有节点都是root的祖先节点。
那么无论当前到何处,只要root不为零,且root不等于 z那么给trace加入root节点作为z的父节点
是正确的,
*/
if(root != 0)
{
trace_size = level;
if(root->data == z->data){
if(z==root) return 1;
else {
trace[level] = root;
if(search_node(root->right,z,level+1)) return 1;
if(search_node(root->left,z,level+1)) return 1;
}
}else if(root->data < z->data){
trace[level] = root;
return search_node(root->right,z,level+1);
}else{
trace[level] = root;
return search_node(root->left,z,level+1);
}
}
return 0;
}
RBT rb_delete(RBT T,RBT_NODE z)
{
RBT re;
if(z == T){
puts("cann't delete the tree");
}
//trace_size = 1;
//用以找到z的祖先节点
if(!search_node(T->left,z,1)){
puts("why i can't search it");
return 0;
}
//完成z的祖先节点的复制
re = trace[0] = new_node(T);
for(int i = 1;i<trace_size;++i){
trace[i] = copy_node(trace[i],trace[i-1]);
}
//现在尝试检查search node效果
RBT_NODE y =z;
RBT_NODE x,temp;
int y_original_color = y->color;
if(z->left == 0)
{
//此时y=z,x为z的孩子
//完成x和x的祖先节点的复制
x = z->right;
rb_transplant(z,x);
}else if(z->right == 0)
{
//完成x和x的祖先节点的复制
x = z->left;
//x = new_node(temp);
rb_transplant(z,x);
}else{
int temp = trace_size;
//试图向trace中添加z
trace[trace_size++] = z;
y = tree_minimum(T,z->right);
//for(int i = 0;i<trace_size;i++){
// printf("%p ->left = %p ->right = %p \n",trace[i],trace[i]->left,trace[i]->right);
//}
y_original_color = y->color;
x = y->right;
if(trace[trace_size-1] != z){
for(int i = temp;i<trace_size;++i){
trace[i] = copy_node(trace[i],trace[i-1]);
}
y = copy_node(y,trace[trace_size-1]);
rb_transplant(y,y->right);
y->right = z->right;
//y->right->parent = y;
}else
y = new_node(y);
int k = trace_size;
trace_size = temp;
rb_transplant(z,y);
trace[trace_size] = y;
trace_size = k;
y->left = z->left;
//y->left->parent = y;
y->color = z->color;
}
if(y_original_color == BLACK)
rb_delete_fixup(re,x);
return re;
}
void print(RBT T,RBT_NODE N)
{
if(N != 0){
printf("data = %d color = %d size = %d ",N->data,N->color,N->size);
if(N->left!=0)
printf("N->left->data = %d ", N->left->data);
if(N->right!=0)
printf("N->right->data = %d ", N->right->data);
puts("");
print(T,N->left);
print(T,N->right);
}
}
int main()
{
struct node T = RBTREE_INIT(&T);
RBT_NODE in[10000];
RBT_NODE tree = &T;
RBT_NODE tree_5k,tree_use;
freopen(".//data1.txt","r",stdin);
freopen(".//out21.txt","w",stdout);
for(int i = 0;i< 10000;i++)
{
in[i] = (RBT_NODE)malloc(sizeof(struct node));
//in[i]->data = rand()%100000;
scanf("%d",&in[i]->data);
//printf("%d ",in[i]->data);
tree = rb_insert(tree,in[i]);
//puts("-----------------------------------------------------------------");
trace[0] = tree;
valid = 0;
if(!check(tree,tree->left,1)){
puts("error");
print(tree,tree->left);
return 0;
}
if(i == 5000){
tree_5k = tree;
//print(tree,tree->left);
}
}
tree_5k = tree;
///puts("-----------------------------------------------------------------");
for(int i = 0;i<10000;++i)
{
//printf("i = %d\n",i);
rb_delete(tree,tree->left);
trace[0] = tree;
valid = 0;
if(!check(tree,tree->left,1)){
puts("error");
//print(tree,tree->left);
return 0;
}
if(i == 5000){
tree_use = tree;
}
}
print(tree_5k,tree_5k->left);
print(tree_use,tree_use->left);
return 0;
}