標籤:style class blog code color 使用
由於只看到13.3節,所以暫時只實現旋轉和插入函數。
思考:如果不帶父結點,那麼在需要訪問z的父結點時,我們可以藉助尋找函數從根結點到待尋找結點z的路徑上必然能找到z的父結點和祖父結點,所以由此可訪問父結點。不過這種方法使得旋轉函數時間增加到O(lgn),而插入函數也相應的增加到O(lgnlgn)。節省了空間上的記憶體,同時增加了已耗用時間。
具體代碼如下:
#include <iostream>using namespace std;#define BLACK 0#define RED 1#define Nil -1#define LEN sizeof(struct Tree)struct Tree{ struct Tree*left; struct Tree*right; int key; int color;};struct Tree*root=NULL;struct Tree*nil=NULL;//非遞迴版本的二叉尋找樹尋找函數struct Tree*ITERATIVE_TREE_SEARCH(struct Tree*x,int k,struct Tree*&p1,struct Tree*&p2){//while (x!=nil&&k!=x->key){p1=x;if (k<x->key){x=x->left;}else x=x->right;if(k!=x->key)//如果沒找到了待尋找值,那麼繼續記錄其祖父和父結點值。{ p2=p1;p1=x;}}return x;}void LEFT_ROTATE(struct Tree*T,struct Tree*x){//左旋轉:分三個步驟①②③來敘述旋轉代碼的。struct Tree*p1=nil,*p2=nil; struct Tree*y=x->right;//設定y結點。x->right=y->left;//本行代碼以及下面的if結構表達的是“y的左孩子成為x的右孩子”。① ITERATIVE_TREE_SEARCH(root,x->key,p1,p2);if(p1==nil)//本行代碼以及下面的if-else結構表達的過程是“y成為該子樹新的根”。②{ root=y;}else if(x==p1->left){ p1->left=y;}else p1->right=y;y->left=x;//本行代碼以及下面一行都表達了“x成為y的左孩子”。③}void RIGHT_ROTATE(struct Tree*T,struct Tree*x){//右旋轉struct Tree*p1=nil,*p2=nil; struct Tree*y=x->left;x->left=y->right; ITERATIVE_TREE_SEARCH(root,x->key,p1,p2);if(p1==nil){root=y;}else if(x==p1->right){p1->right=y;}else p1->left=y;y->right=x;}void RB_INSERT_INSERT_FIXUP(struct Tree*T,struct Tree*z){ struct Tree*p1=nil,*p2=nil; ITERATIVE_TREE_SEARCH(root,z->key,p1,p2);//p1=z->parent,p2=z->parent->parent while (1) { ITERATIVE_TREE_SEARCH(root,z->key,p1,p2);//p1是父結點 p2是祖父結點 if (p1->color!=RED) { break; } if (p1==p2->left) { struct Tree*y=p2->right;//叔結點 if (y->color==RED)//情況一:叔結點為紅色 {//給p1,y,p2著色以保持性質5。並且解決了z的父結點和z都是紅色結點問題 p1->color=BLACK; y->color=BLACK; p2->color=RED; z=p2;//把z的祖父結點當成新結點z進入下一次迴圈 } else { if (z==p1->right)//情況二:檢查z是否是一個右孩子且叔結點為黑色,前提是p1結點不是葉子結點 {//使用一個左旋讓情況2轉變為情況3 z=p1; LEFT_ROTATE(T,z);//由於進入if語句後可知旋轉結點不可能是葉子結點,這樣就不用判斷z是否是葉子結點了。 ITERATIVE_TREE_SEARCH(root,z->key,p1,p2);//p1=z->parent,p2=z->parent->parent } p1->color=BLACK;//情況三:是z是一個左孩子且叔結點為黑色,改變z的父和祖父結點顏色並做一次右旋,以保持性質5。 p2->color=RED; if(p2!=nil) RIGHT_ROTATE(T,p2);//由於p2可能是葉子結點,所以最好還是用一個if判斷 } } else//下面else分支類似於上面 { struct Tree*y=p2->left; if (y->color==RED) { p1->color=BLACK; y->color=BLACK; p2->color=RED; z=p2; } else { if (z==p1->left) { z=p1; RIGHT_ROTATE(T,z); ITERATIVE_TREE_SEARCH(root,z->key,p1,p2); } p1->color=BLACK; p2->color=RED; if(p2!=nil) LEFT_ROTATE(T,p2); } } } root->color=BLACK;//最後給根結點著為黑色。}void RB_INSERT(struct Tree*T,struct Tree*z){struct Tree*y=nil;struct Tree*x=root;while (x!=nil){y=x;if (z->key<x->key){x=x->left;}else x=x->right;}if (y==nil){root=z;} else if(z->key<y->key){y->left=z;}else y->right=z;z->left=nil;z->right=nil;z->color=RED;RB_INSERT_INSERT_FIXUP(T,z);}//中序遍曆void InOderTraverse(struct Tree *p){ if (p!=nil){InOderTraverse(p->left);cout<<p->key<<" "<<p->color<<" "<<endl;InOderTraverse(p->right);}}void main(){nil=new struct Tree[LEN];nil->key=Nil;nil->color=BLACK;root=nil;int i=0;struct Tree*ROOT=new struct Tree[LEN];cin>>ROOT->key;RB_INSERT(nil,ROOT);root=ROOT; while (i!=12) {struct Tree*z=new struct Tree[LEN];cin>>z->key;RB_INSERT(root,z);i++; }InOderTraverse(root);}