數(shù)據(jù)結(jié)構(gòu) 紅黑樹的詳解
數(shù)據(jù)結(jié)構(gòu) 紅黑樹的詳解
紅黑樹是具有下列著色性質(zhì)的二叉查找樹:
1.每一個(gè)節(jié)點(diǎn)或者著紅色,或者著黑色。
2.根是黑色的。
3.如果一個(gè)節(jié)點(diǎn)是紅色的,那么它的子節(jié)點(diǎn)必須是黑色。
4.從一個(gè)節(jié)點(diǎn)到一個(gè)NULL指針的每一條路徑必須包含相同數(shù)目的黑色節(jié)點(diǎn)。
下面是一棵紅黑樹。
1.自底向上插入
通常把新項(xiàng)作為樹葉放到樹中。如果我們把該項(xiàng)涂成黑色,那么違反條件4,因?yàn)閷?huì)建立一條更長(zhǎng)的黑節(jié)點(diǎn)路徑。因此這一項(xiàng)必須涂成紅色。如果它的父節(jié)點(diǎn)是黑色的,插入完成。如果父節(jié)點(diǎn)是紅色的,那么違反條件3。在這種情況下我們必須調(diào)整該樹以滿足條件3。用于完成這項(xiàng)目任務(wù)的基本操作是顏色的改變和樹的旋轉(zhuǎn)。
如果新插入的節(jié)點(diǎn)的父節(jié)點(diǎn)是黑色,那么插入完成。
如果父節(jié)點(diǎn)是紅色,那么有幾種情形需要考慮。首先,假設(shè)這個(gè)父節(jié)點(diǎn)的兄弟是黑色(NULL節(jié)點(diǎn)約定為黑色)。這對(duì)于插入3或8是適用的,但對(duì)插入99不適用。令X是新加的樹葉,P是它的父節(jié)點(diǎn),S是該父節(jié)點(diǎn)的兄弟,G是祖父節(jié)點(diǎn)情況一:父節(jié)點(diǎn)的兄弟是黑色的。通過操作使得到達(dá)A,B,C的黑色路徑保持不變(滿足條件4),而且沒有連續(xù)的紅色節(jié)點(diǎn)(滿足條件3).。
情況二:父節(jié)點(diǎn)的兄弟是紅色的。
2.自頂向下刪除
紅黑樹中的刪除可以是自頂向下進(jìn)行。每一件工作都?xì)w結(jié)于能夠刪除一片樹葉。這是因?yàn)?,要?jiǎng)h除一個(gè)帶有兩個(gè)兒子的節(jié)點(diǎn),我們用右子樹上的最小節(jié)點(diǎn)代替它;該節(jié)點(diǎn)最多有一個(gè)兒子,然后將該節(jié)點(diǎn)刪除。只有一個(gè)右兒子的節(jié)點(diǎn)可以用相同的方式刪除,而只有一個(gè)左兒子的節(jié)點(diǎn)通過用其左子樹上最大的節(jié)點(diǎn)替換,然后可將該節(jié)點(diǎn)刪除。但是假如刪除的節(jié)點(diǎn)不是紅色的,那么就會(huì)破壞紅黑樹的平衡。解決的方法就是保證從上到下刪除期間樹葉是紅色的。




// // RedBlackTree.h // RedBlackTree3 // // Created by Wuyixin on 2017/7/3. // Copyright © 2017年 Coding365. All rights reserved. // #ifndef RedBlackTree_h #define RedBlackTree_h #include <stdio.h> #include <stdlib.h> #include <limits.h> typedef int ElementType; typedef enum { RED, BLACK } COLOR; typedef struct RedBlackNode *RedBlackTree,*Position; struct RedBlackNode{ ElementType Element; COLOR Color; RedBlackTree Left; RedBlackTree Right; }; static Position NullNode = NULL; static Position Header; static Position X,P,GP,GGP; /* 初始化 */ RedBlackTree Initialize(); /* 插入 */ RedBlackTree Insert(RedBlackTree T,ElementType Item); /* 刪除 */ RedBlackTree Remove(RedBlackTree T,ElementType Item); /* 查找 */ Position Find(RedBlackTree T,ElementType Item); /* 遍歷 */ void Travel(RedBlackTree T); #endif /* RedBlackTree_h */
3.2 實(shí)現(xiàn)文件
// // RedBlackTree.c // RedBlackTree3 // // Created by Wuyixin on 2017/7/3. // Copyright © 2017年 Coding365. All rights reserved. // #include "RedBlackTree.h" /* 左旋轉(zhuǎn) */ static Position SingleRotateLeft(Position X); /* 右旋轉(zhuǎn) */ static Position SingleRotateRight(Position X); /* 旋轉(zhuǎn) */ static Position Rotate(Position Parent,Position* Origin ,ElementType Item); /* 左旋轉(zhuǎn) */ static Position SingleRotateLeft(Position T){ Position TL = T->Left; T->Left = TL->Right; TL->Right = T; return TL; } /* 右旋轉(zhuǎn) */ static Position SingleRotateRight(Position T){ Position TR = T->Right; T->Right = TR->Left; TR->Left = T; return TR; } /* 旋轉(zhuǎn) */ static Position Rotate(Position Parent,Position* Origin ,ElementType Item){ if (Item < Parent->Element){ if (Origin != NULL) *Origin = Parent->Left; return Parent->Left = Item < Parent->Left->Element ? SingleRotateLeft(Parent->Left) : SingleRotateRight(Parent->Left); } else{ if (Origin != NULL) *Origin = Parent->Right; return Parent->Right = Item < Parent->Right->Element ? SingleRotateLeft(Parent->Right) : SingleRotateRight(Parent->Right); } } /* 初始化 */ RedBlackTree Initialize(){ if (NullNode == NULL){ NullNode = malloc(sizeof(struct RedBlackNode)); if (NullNode == NULL) exit(EXIT_FAILURE); NullNode->Element = INT_MAX; NullNode->Color = BLACK; NullNode->Left = NullNode->Right = NullNode; } Header = malloc(sizeof(struct RedBlackNode)); if (Header == NULL) exit(EXIT_FAILURE); /* header的值為無窮小,所以根插入到右邊*/ Header->Element = INT_MIN; Header->Left = Header->Right = NullNode; Header->Color = BLACK; return Header; } static Position GetSibling(Position Parent,Position X){ if (Parent->Element == INT_MIN) return NULL; if (X == Parent->Left) return Parent->Right; else if (X == Parent->Right) return Parent->Left; else return NULL; } void HandleReorientForInsert(ElementType Item){ Position Sibling,Origin; /* 當(dāng)P與X同時(shí)為紅節(jié)點(diǎn)才進(jìn)行調(diào)整 */ if (X == NullNode || !(P->Color == RED && X->Color == RED)) return ; Sibling = GetSibling(GP, P); if (Sibling == NULL) return ; /* GP,P,X是成字型,調(diào)整為一字型 */ if ((GP->Element < Item) != (P->Element < Item)){ P = Rotate(GP, &Origin,Item); X = Origin; } GP = Rotate(GGP, &Origin,Item); P = Origin; /* P的兄弟是黑色的 */ if (Sibling->Color == BLACK){ GP->Color = BLACK; GP->Left->Color = RED; GP->Right->Color = RED; } /* P的兄弟是紅的 */ else{ GP->Color = RED; GP->Left->Color = BLACK; GP->Right->Color = BLACK; } } RedBlackTree _Insert(RedBlackTree T,ElementType Item){ if (T == NullNode){ T = malloc(sizeof(struct RedBlackNode)); T->Element = Item; T->Left = T->Right = NullNode; T->Color = RED; } else if (Item < T->Element) T->Left = _Insert(T->Left, Item); else if (Item > T->Element) T->Right = _Insert(T->Right, Item); /* 重復(fù)值不插入 */ X = P,P = GP,GP = GGP, GGP = T; HandleReorientForInsert(Item); return T; } /* 插入 */ RedBlackTree Insert(RedBlackTree T,ElementType Item){ GGP = GP = P = X = NullNode; T = _Insert(T, Item); T->Right->Color = BLACK; return T; } static void _HandleReorientForRemove(ElementType Item){ RedBlackTree Sibling,R; Sibling = GetSibling(P, X); if (Sibling == NULL) return ; if (Sibling->Left->Color == BLACK && Sibling->Right->Color == BLACK){ P->Color = BLACK; X->Color = RED; Sibling->Color = RED; }else if(Sibling->Left->Color == RED){ R = Sibling->Left; P->Color = BLACK; X->Color = RED; R = Rotate(P, NULL, R->Element); GP = Rotate(GP, NULL, R->Element); }else if (Sibling->Right->Color == RED){ X->Color = RED; P->Color = BLACK; Sibling->Color = RED; Sibling->Right->Color = BLACK; GP = Rotate(GP, NULL, Sibling->Element); } } static void HandleReorientForRemove(RedBlackTree T, ElementType Item){ RedBlackTree Sibling,Origin,OriginGP; if (X == NullNode) return ; /* X有兩個(gè)黑兒子 */ if (X->Left->Color == BLACK && X->Right->Color == BLACK){ _HandleReorientForRemove(Item); }else{ OriginGP = GP; /* 落到下一層 */ GP = P; P = X; if (Item < X->Element) X = X->Left; else X = X->Right; Sibling = GetSibling(P, X); /* 如果X是黑的,則Sibling是紅的,旋轉(zhuǎn) */ if (X->Color == BLACK){ GP = Rotate(GP, &Origin, Sibling->Element); P = Origin; GP->Color = BLACK; P->Color = RED; _HandleReorientForRemove(Item); } /* 恢復(fù)X,PX,GP。由于X是當(dāng)前節(jié)點(diǎn) 如果當(dāng)前節(jié)點(diǎn)正是Item,不恢復(fù)會(huì)影響查找 */ if (X->Element == Item){ X = P ; P = GP ;GP = OriginGP; } } } /* 刪除 */ RedBlackTree Remove(RedBlackTree T,ElementType Item){ ElementType Origin; Position DeletePtr; Origin = NullNode->Element; NullNode->Element = Item; GP = P = X = T; /* 根染紅 */ T->Right->Color = RED; while (X->Element != Item) { GP = P ; P = X; if (Item < X->Element) X = X->Left; else X = X->Right; HandleReorientForRemove(T, Item); } NullNode->Element = Origin; /* 找到 */ if (X != NullNode){ DeletePtr = X; if (X->Left != NullNode){ GP = P ; P = X; X = X->Left; HandleReorientForRemove(T, Item); /* 尋找左子樹最大值替換 */ while (X->Right != NullNode) { GP = P ; P = X; X = X->Right; HandleReorientForRemove(T, Item); } if (X == P->Left) P->Left = X->Left; else P->Right = X->Left; }else if (X->Right != NullNode){ GP = P ; P = X; X = X->Right; HandleReorientForRemove(T, Item); /* 尋找右子樹最大值替換 */ while (X->Left != NullNode) { GP = P ; P = X; X = X->Left; HandleReorientForRemove(T, Item); } if (X == P->Left) P->Left = X->Right; else P->Right = X->Right; }else{ /* X是樹葉 */ if (X == P->Left) P->Left = NullNode; else P->Right = NullNode; } DeletePtr->Element = X->Element; free(X); } /* 根染黑 */ T->Right->Color = BLACK; return T; } typedef enum { ROOT, LEFT, RIGHT } NodeType; static char *TypeC; static char *ColorC; void _Travel(RedBlackTree T , NodeType Type){ if (T != NullNode){ if (Type == ROOT) TypeC = "root"; else if (Type == LEFT) TypeC = "left"; else if (Type == RIGHT) TypeC = "right"; if (T->Color == BLACK) ColorC = "black"; else ColorC = "red"; printf("(%d,%s,%s) ",T->Element,ColorC,TypeC); _Travel(T->Left, LEFT); _Travel(T->Right, RIGHT); } } /* 遍歷 */ void Travel(RedBlackTree T){ _Travel(T->Right,ROOT); }
3.3 調(diào)用
// // main.c // RedBlackTree3 // // Created by Wuyixin on 2017/7/3. // Copyright © 2017年 Coding365. All rights reserved. // #include "RedBlackTree.h" int main(int argc, const char * argv[]) { RedBlackTree T = Initialize(); T = Insert(T, 10); T = Insert(T, 85); T = Insert(T, 15); T = Insert(T, 70); T = Insert(T, 20); T = Insert(T, 60); T = Insert(T, 30); T = Insert(T, 50); T = Insert(T, 65); T = Insert(T, 80); T = Insert(T, 90); T = Insert(T, 40); T = Insert(T, 5); T = Insert(T, 55); T = Insert(T, 100); T = Remove(T, 100); Travel(T); return 0; }
以上就是關(guān)于數(shù)據(jù)結(jié)構(gòu)與算法中紅黑二叉樹的詳解,如有疑問請(qǐng)留言或者到本站的社區(qū)討論,感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!
相關(guān)文章
C++進(jìn)一步認(rèn)識(shí)類與對(duì)象
類是創(chuàng)建對(duì)象的模板,一個(gè)類可以創(chuàng)建多個(gè)對(duì)象,每個(gè)對(duì)象都是類類型的一個(gè)變量;創(chuàng)建對(duì)象的過程也叫類的實(shí)例化。每個(gè)對(duì)象都是類的一個(gè)具體實(shí)例(Instance),擁有類的成員變量和成員函數(shù)2021-10-10C++ Primer Plus 第四章之C++ Primer Plus復(fù)合類型學(xué)習(xí)筆記
數(shù)組(array)是一種數(shù)據(jù)格式,能夠存儲(chǔ)多個(gè)同類型的值。每個(gè)值都存儲(chǔ)在一個(gè)獨(dú)立的數(shù)組元素中,計(jì)算機(jī)在內(nèi)存中依次存儲(chǔ)數(shù)組的各個(gè)元素,今天給大家重點(diǎn)介紹C++ Primer Plus復(fù)合類型的實(shí)例詳解,感興趣的朋友一起看看吧2021-07-07Opencv下載和導(dǎo)入Visual studio2022的實(shí)現(xiàn)步驟
本文主要介紹了Opencv下載和導(dǎo)入Visual studio2022的實(shí)現(xiàn)步驟,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05C++實(shí)現(xiàn)LeetCode(157.用Read4來讀取N個(gè)字符)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(157.用Read4來讀取N個(gè)字符),本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07