算法导论思考题13-1:持久动态集合中的持久二叉搜索树
来源:互联网 发布:证件照软件 编辑:程序博客网 时间:2024/06/13 05:36
目标:实现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 != NullRBT_NODE parent = trace[trace_size - 1];//parent为x的父母,x!=Nullstruct node * y = x->right;//parent为x的父母,x!=Null,y等于x->rightif(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中添加ztrace[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;}elsey = 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;}
- 算法导论思考题13-1:持久动态集合中的持久二叉搜索树
- 算法导论-13-1-持久动态集合
- 算法导论-13-1-持久动态集合
- 算法导论-13-1-持久动态集合
- 算法导论 第13章 13-1 持久动态集合
- 算法导论12章二叉搜索树 思考题总结
- 用二叉查找树实现持久动态集合
- 持久动态集合的二叉查找树实现
- 算法导论 思考题 13-1
- 《算法导论》动态规划-思考题
- 算法导论 思考题 13-3(AVL树)
- 动态规划之最优二叉搜索树(算法导论)
- 【算法导论】动态规划之“最优二叉搜索树”
- 算法导论之动态规划:最优二叉搜索树
- 算法导论-----二叉搜索树
- 算法导论-----------二叉搜索树
- 算法导论 二叉搜索树
- 算法导论--二叉搜索树
- sshSSH Secure Shell Client root用户无法登录解决办法
- USACO-Section1.3 Mixing Milk【贪心算法】
- 51nod1536 不一样的猜数游戏
- c语言入门:文件读写操作
- ubuntu安装openssh-server 报依赖错误的解决过程
- 算法导论思考题13-1:持久动态集合中的持久二叉搜索树
- 练习11
- 练习12
- 面向对象程序设计第三次实验课——Wuxing
- 正则表达式NFA.java
- 练习13
- 海外SDK之----------谷歌登录
- Android 点击事件常用写法
- swing 表格模型增加删除行和列