二叉搜索樹的結構:算法
typedef int ElemType; typedef struct SearchBiTree { ElemType Data; struct SearchBiTree *LChild,*RChild,*Parent; }SearchBiTree,*PSearchBiTree;
二叉搜索樹的性質:函數
設 x 是二叉搜索樹中的一個節點。若是 y 是 x 左子樹中的一個節點,那麼 y.data <= x.data。spa
若是 y 是 x 右子樹中的一個節點,那麼 y.data >= x.data。3d
不一樣的二叉搜索樹能夠表明同一組值的集合。code
插入代碼:blog
void Tree_Insert(PSearchBiTree &T,PSearchBiTree z) { PSearchBiTree y = NULL; PSearchBiTree x = T; while(x != NULL) { y = x; if(z->Data < x->Data) x = x->LChild; else x = x->RChild; } z->Parent = y; if(y == NULL) T = z; else if(z->Data < y->Data) y->LChild = z; else y->RChild = z; }
刪除操做:class
刪除操做共有以下四種狀況:搜索
右下角的那種狀況 Min 結點是 R子樹中值最小的一個結點,因此它的左孩子爲空。im
刪除代碼:db
一、替換函數:將結點 v 替換 T 樹中的結點 u。
void Transplant(PSearchBiTree &T,PSearchBiTree u,PSearchBiTree v) { if(u->Parent == NULL) T = v; else if(u == u->Parent->LChild) u->Parent->LChild = v; else u->Parent->RChild = v; if(v != NULL) v->Parent = u->Parent; }
二、結點中的最小值。
PSearchBiTree Tree_Minimum(PSearchBiTree T) { while(T->LChild != NULL) T = T->LChild; return T; }
三、刪除結點 z。
void Tree_Delete(PSearchBiTree &T,PSearchBiTree z) { PSearchBiTree y = NULL; if(z->LChild == NULL) Transplant(T,z,z->RChild); else if(z->RChild == NULL) Transplant(T,z,z->LChild); else { y = Tree_Minimum(z->RChild); if(y->Parent == z) { Transplant(T,y,y->RChild); y->RChild = z->RChild; y->RChild->Parent = y; } Transplant(T,z,y); y->LChild = z->LChild; y->LChild->Parent = y;
}
}
紅黑樹:
算法導論中樹的高度彷佛並不算樹根。
紅黑樹是許多"平衡"搜索樹中的一種,能夠保證在最壞狀況下基本動態集合操做的時間複雜度爲O(lgn)。
紅黑樹是一顆二叉搜索樹,它相對二叉搜索樹增長了一個存儲位來標識結點顏色,可使 Red 或 Black。
經過對任何一條從根到葉子的簡單路徑上各個結點的顏色進行約束,確保沒有一條路徑會比其餘路徑長出兩倍。
咱們一般把帶關鍵字的結點稱爲內部結點,不帶關鍵字的結點而且其沒有子結點或父結點的結點稱爲外部結點。
紅黑樹結構:
typedef enum {Red,Black}RB_Color; typedef struct RBTree { ElemType Data; struct RBTree *Left,*Right,*Parent; RB_Color Color; }RBTree,*PRBTree;
紅黑性質:
一、每一個結點或是紅色的,或是黑色的。
二、根節點是黑色的。
三、每一個葉結點是黑色的。
四、若是一個結點是紅色的,則它的兩個子結點都是黑色的。
五、對每個結點,從該結點到其後代葉結點的簡單路徑上,均包含相同數目的黑色結點。
黑高bh:從某個結點 x 出發(不含該結點)到達一個葉結點的任意一條簡單路徑上的黑色結點個數,記做 bh(x)。
引理:一顆有 n 個內部結點的紅黑樹的高度至多爲 2lg(n+1)。
推論:一顆高度爲 h 的紅黑樹,黑高bh 至少爲 (h/2)向上取整,最多爲 h。
至少有 2^bh - 1 個結點,最多有 4^bh - 1個結點。
旋轉操做:
如圖,從右到左爲左旋,從左到右爲右旋。
旋轉代碼:
void Left_Rotate(PRBTree &T,PRBTree x) { PRBTree y = x->Right; x->Right = y->Left; if(y->Left != NULL) y->Left->Parent = x; y->Parent = x->Parent; if(x->Parent == NULL) T = y; else if(x == x->Parent->Left) x->Parent->Left = y; else x->Parent->Right = y; y->Left = x; x->Parent = y; } void Right_Rotate(PRBTree &T,PRBTree y) { PRBTree x = y->Left; y->Left = x->Right; if(x->Right != NULL) x->Right->Parent = y; x->Parent = y->Parent; if(y->Parent == NULL) T = x; else if(y == y->Parent->Left) y->Parent->Left = x; else y->Parent->Right = x; x->Right = y; y->Parent = x; }
插入操做:
在進行編寫代碼以前,須要分析一下全部的插入狀況:
1、插入結點 A 的父結點 B 爲黑色,此時插入不會破壞紅黑樹的性質。
2、插入結點 A 的父結點 B 爲紅色,且 B 結點的兄弟也爲紅色,
這時將不知足性質 4。但能夠做相應調整:
此時,將 B 結點以及 C 結點 變成黑色,將 D 結點變成紅色便可。
3、插入結點 A 的父結點 B 爲紅色,可是 B 結點的兄弟爲黑色,
這是也不知足性質 4,也能夠做出相應調整:
分別對以上四圖變化後,對圖1、圖二先變色後,分別右旋 DB,左旋 DB。
而圖3、圖四分別左旋 BA,右旋 BA 後,就變成了圖1、圖二。
相關操做以下所示:
插入代碼:
void RB_Insert(PRBTree &T,PRBTree z) { PRBTree y = NULL; PRBTree x = T; while(x != NULL) { y = x; if(z->Data < x->Data) x = x->Left; else x = x->Right; } z->Parent = y; if(y == NULL) T = z; else if(z->Data < y->Data) y->Left = z; else y->Right = z; z->Left = NULL; z->Right = NULL; z->Color = Red; RB_Insert_Fixup(T,z); }
插入修正代碼:
void RB_Insert_Fixup(PRBTree &T,PRBTree z) { PRBTree y = NULL; while(z->Parent->Color = Red) { if(z->Parent == z->Parent->Parent->Left) { y = z->Parent->Parent->Right; if(y->Color == Red) { z->Parent->Color = Black; y->Color = Black; z->Parent->Parent->Color = Red; z = z->Parent->Parent; } else if(z = z->Parent->Right) { z = z->Parent; Left_Rotate(T,z); } z->Parent->Color = Black; z->Parent->Parent->Color = Red; Right_Rotate(T,z->Parent->Parent); } else { y = z->Parent->Parent->Left; if(y->Color = Red) { z->Parent->Color = Black; y->Color = Black; z->Parent->Parent->Color = Red; z = z->Parent->Parent; } else if(z == z->Parent->Left) { z = z->Parent; Left_Rotate(T,z); } z->Parent->Color = Black; z->Parent->Parent->Color = Red; Left_Rotate(T,z->Parent->Parent); } } T->Color = Black; }
刪除操做:
與 n 個結點的紅黑樹上的其餘的基本操做同樣,刪除一個結點須要花費 O(lgn) 時間。
下面給出幾種刪除狀況:
1、先給出簡單的刪除狀況:被刪除結點 A 爲 紅色,結點 A 的兄弟和孫子沒有畫出。
這幾種狀況能夠直接將結點 A 爲刪除,紅黑樹性質不會被破壞。
刪除結點 A 後狀況以下圖:
2、比較複雜的就是以下左邊的這種圖,由於此時會破壞紅黑性質 5 或可能破壞紅黑性質 4。
讓咱們先來分析一下,A 的父結點和子孫結點顏色不肯定,用藍色表示。
如若咱們刪除 A 結點,則須要尋找一個結點替代結點 A 的位置並變成結點 A 的顏色。
咱們能夠尋找比 A 小且相鄰的結點,也就是 A 的右子樹中最小的一個結點,用 Min 表示。
咱們任然不知道結點 Min 的顏色,這裏先分析簡單的,讓它以紅色表示。
由於要保持紅黑性質,因此有以下兩種狀況:
這兩種狀況只須要簡單的將 Min 結點替換到 A 的位置並將顏色變成 A 的顏色便可。
3、任然是上面左邊兩個圖,當結點 Min 的顏色是黑色時,狀況就比較複雜了。
由於當移走黑色的結點 Min 後,會破壞紅黑性質 5,可能會破壞紅黑性質 4。
一、當 Min 結點的右孩子 C 爲紅色時的狀況以下:
這種狀況比較簡單,只須要將 C 結點替換到 Min 結點的位置並將顏色變成黑色便可解決問題。
Min 的兄弟結點只畫了一種狀況,其餘狀況也同樣,但要保持紅黑性質。
二、當 Min 結點的右孩子爲黑色時的狀況以下:
當 Min 結點刪除後,咱們須要找到一個紅結點填到 Min 的那個路徑上,並將顏色變成黑色。
因此當 P 的顏色爲紅色時,咱們只須要左旋一下 PB,並將 P結點顏色變成黑色便可。
可是當 P 的顏色爲黑色時,咱們就得在 P 的右子樹中尋找一個紅結點了。
所以咱們把這兩種狀況和成一種狀況,就是把 P 的顏色看成黑色討論。
3.一、對於前三個圖,咱們能夠歸爲一種狀況:也就是第二個圖的那種狀況:
第二張圖的特色是 Min 結點的兄弟的右孩子 C 爲 紅色:
咱們先將 PB 左旋,而後顏色互換,再將 C 結點的顏色變成黑色便可。
第三個圖是先將 DC 右旋,而後顏色互換,就變成了第二張圖的狀況。
3.二、對於第五個圖其實能夠和第四個圖同爲一種狀況。
咱們已經沒法在 P 樹的內部尋找到一個合適的紅色結點來替換 Min 的位置了。
因此此時咱們得在 P 樹的祖先中尋找一個紅色結點來增長 P 樹的樹高。
咱們將 P 結點設爲新的起始點,代替原來 Min 的右結點也就是空結點。
當 P 做爲新的起始點後,咱們須要判斷 P 結點是其父結點的左孩子仍是右孩子。
若是是左孩子則執行相同的操做,不然便將該左旋的地方右旋,該右旋的地方左旋,
屬性爲 left 的地方變成 right,屬性爲 right 的地方變成 left。
總而言之,就是左右互換就對了。最後將起始點顏色變成黑色。
刪除代碼:
一、紅黑樹替換和尋找最小值:
void RB_Transplant(PRBTree &T,PRBTree u,PRBTree v) { if(u->Parent == NULL) T = v; else if(u == u->Parent->Left) u->Parent->Left = v; else u->Parent->Right = v; v->Parent = u->Parent; } PRBTree RBTree_Minimum(PRBTree T) { while(T->Left != NULL) T = T->Left; return T; }
二、紅黑樹刪除:
void RB_Delete(PRBTree &T,PRBTree z) { PRBTree y = z; PRBTree x = NULL; RB_Color Original_Color = y->Color; if(z->Left = NULL) { x = z->Right; RB_Transplant(T,z,z->Right); } else if(z->Right == NULL) { x = z->Left; RB_Transplant(T,z,z->Left); } else { y = RBTree_Minimum(z->Right); Original_Color = y->Color; x = y->Right; if(y->Parent == z) x->Parent = y; else { RB_Transplant(T,y,y->Right); y->Right = z->Right; y->Right->Parent = y; } RB_Transplant(T,z,y); y->Left = z->Left; y->Left->Parent = y; y->Color = z->Color; } if(Original_Color == Black) RB_Delete_Fixup(T,x); }
三、紅黑樹修正:
void RB_Delete_Fixup(PRBTree &T,PRBTree x) { PRBTree w = NULL; while(x != T && x->Color == Black) { if(x == x->Parent->Left) { w = x->Parent->Right; if(w->Color == Red) { w->Color = Black; x->Parent->Color = Red; Left_Rotate(T,x->Parent); w = x->Parent->Right; } if(w->Left->Color == Black && w->Right->Color == Black) { w->Color = Red; x = x->Parent; } else { if(w->Right->Color == Black) { w->Left->Color = Black; w->Color = Red; Right_Rotate(T,w); w = x->Parent->Right; } w->Color = x->Parent->Color; x->Parent->Color = Black; w->Right->Color = Black; Left_Rotate(T,x->Parent); x = T; } } else { w = x->Parent->Left; if(w->Color == Red) { w->Color = Black; x->Parent->Color = Red; Right_Rotate(T,x->Parent); w = x->Parent->Left; } if(w->Right->Color == Black && w->Left->Color == Black) { w->Color = Red; x = x->Parent; } else { if(w->Left->Color == Black) { w->Right->Color = Black; w->Color = Red; Left_Rotate(T,w); w = x->Parent->Left; } w->Color = x->Parent->Color; x->Parent->Color = Black; w->Left->Color = Black; Right_Rotate(T,x->Parent); x = T; } } } x->Color = Black; }
如有錯誤請多擔待,謝謝!