關於紅/黑樹狀結構的故事:
如果被刪的是紅結點,那麼沒影響
如果是黑結點,那麼它死了,但它留下了它黑色的魂來支撐整個紅/黑樹狀結構的結構,讓這棵樹暫時看起來合法。但畢竟這個魂是多餘的,它需要附著在其它節點上,以至於有的點成了“雙重黑”,於是需要不斷地把這個黑魂往上擠,其間這個魂都是存在的,也就是說這棵樹一直被你假裝成合法的,直到這個黑魂被你擠出這棵樹那麼就真的合法了。
以下是我個人的理解,我覺得還是將x路看作少了一個黑點來理解更容易一些。
刪除部分:
代碼:
#include<iostream>#include<string>using namespace std;#define black 1#define red 0struct node{node* p;node* left;node* right;int key;bool color;node(){}node(node* init,int k):p(init),left(init),right(init),key(k),color(black){}};struct tree{node* root;node* nil;tree(){root=new node(NULL,-1),nil=root;}};node* tree_Minimum(tree* t,node *x) //找比x小的值,一直往左遍曆{ while(x->left != t->nil) x = x->left; return x; } node* search(tree* t,int key){node* x=t->root;while(x!=t->nil && x->key !=key){if(key < x->key)x=x->left;else x=x->right;}if(x==t->nil)//找不到{cout<<"Search Failed!"<<endl;exit(1);//暴力關閉,I like it,但是不和諧}return x;}void left_rotate(tree* t,node* x){node* 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;x->p=y;y->left=x;}void right_rotate(tree* t,node* x){node* y=x->left;x->left=y->right;if(y->right!=t->nil)y->right->p=x;y->p=x->p;if(x->p==t->nil)t->root=y;else if(x==x->p->right)x->p->right=y;else x->p->left=y;x->p=y;y->right=x;}void rb_insert_fixup(tree* t,node* z){node* y;while(z->p->color==red){if(z->p==z->p->p->left){y=z->p->p->right;if(y->color==red){z->p->color=black;y->color=black;y->p->color=red;z=z->p->p;}else {if(z==z->p->right){z=z->p;left_rotate(t,z);}z->p->color=black;z->p->p->color=red;right_rotate(t,z->p->p);}}else {y=z->p->p->left;if(y->color==red){z->p->color=black;y->color=black;y->p->color=red;z=z->p->p;}else {if(z==z->p->left){z=z->p;right_rotate(t,z);}z->p->color=black;z->p->p->color=red;left_rotate(t,z->p->p);}}}t->root->color=black;}void rb_insert(tree* t,node* z){node* y=t->nil;node*x=t->root;while(x!=t->nil){y=x;if(z->key < x->key)x=x->left;else x=x->right;}z->p=y;if(y==t->nil)t->root=z;else if(z->key < y->key)y->left=z;else y->right=z;z->left=t->nil;z->right=t->nil;z->color=red;rb_insert_fixup(t,z);}void print(tree* t,node* x){if(x->key==-1)//空樹直接返回,因為空白樹的根初始為-1return ;else if(x!=t->nil)//中序遍曆{print(t,x->left);cout<<x->key<<' '<<x->color<<endl;print(t,x->right);}}void rb_delete_fixup(tree* t,node* x){node* w;while(x !=t->root && x->color==black){if(x==x->p->left)//這裡是==,調試寫成了=,謹慎{w=x->p->right;//case 1:if(w->color==red)//case 1:x的兄弟結點w為紅,操作目的:將w轉化為黑,轉化為case 2,3,4{x->p->color=red;w->color=black;left_rotate(t,x->p);w=x->p->right;}//case 2:if(w->left->color==black && w->right->color==black )//case 2:兄弟結點w為黑且w的左右孩子均為黑,{//操作目的:使x子樹和w子樹平衡,因為一開始x路比其它路少1個黑色點,現在將w的黑色塗去,換成紅色,那麼x路和w路平衡,但是,x.p路又比其它路少1個黑色點,因為左右子樹都少了一個黑色點w->color=red; x=x->p; //於是需要將額外的黑色點向上附著在x->p身上形成雙重黑,繼續向上:如果新雙重點原來是紅色,那麼直接塗黑,done,否則繼續}else{//case 3:if(w->right->color==black)//case 3:w為黑,w->right為黑,w->left為紅,操作目的:轉化為case 4{w->color=red;w->left->color=black;right_rotate(t,w);w=x->p->right;}//case 4:w->color=x->p->color;//case 4:可以付儲行動的情況,x路原本少1黑色,現在通過以下操作(exchange_color 和left_rotate),可以將x路黑高加1而其它路的黑高保持不變,則整棵樹平衡,演算法結束x->p->color=black;w->right->color=black;left_rotate(t,x->p);x=t->root;//注意不要寫漏,這裡為了退出迴圈}}else{//與上面對稱,將left-right對調即可w=x->p->left;if(w->color==red){w->color=black;x->p->color=red;right_rotate(t,x->p);w=x->p->left;}if(w->left->color==black && w->right->color==black){w->color=red;x=x->p;}else {if(w->left->color==black){w->color=red;w->right->color=black;right_rotate(t,w);w=x->p->left;}w->color=x->p->color;x->p->color=black;w->left->color=black;right_rotate(t,x->p);x=t->root;x=t->root;}}}x->color=black;}node* rb_delete(tree* t,node* z){node* y;//指向實際要刪的結點node* x;//指向y的下一個結點if(z->left ==t->nil || z->right==t->nil)//1.如果存在其中一個子樹為空白,則刪除的是zy=z;//2.if(z->left !=t->nil && z->right!=t->nil)後繼==z->right子樹的最小值else y=tree_Minimum(t,z->right);//否則刪除z的後繼,由上面可知y最多隻有一個子樹:如果由1而來,存在一個子樹為空白,如果由2而來,後繼必沒有左子樹if(y->left==t->nil)x=y->right;//x指向y的下一個結點else x=y->left;//***********transplant(tree* t,node* y,node* x)的代碼:將x子樹移植到y節點x->p=y->p;if(y->p==t->nil)t->root=x;else if(y==y->p->left)y->p->left=x;else y->p->right=x;//調整指標,刪掉y:將y結點去除,將y->key賦給z->key//****************************************************if(y!=z)z->key = y->key;if(y->color==black)//如果為紅,刪掉一個紅結點,無影響,如果為黑,調用rb_delete_fixup調整rb_delete_fixup(t,x);return y;//返回指標,避免記憶體流失}void main(){int S[]={7,2,11,1,5,8,14,4,15};int len=sizeof(S)/sizeof(S[0]);node* y;tree* t=new tree();for(int i=0;i<len;i++){y=new node(t->nil,S[i]);rb_insert(t,y);}print(t,t->root);rb_delete(t,t->root); cout<<endl;print(t,t->root);}
結果: