日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

STL源码剖析---红黑树原理详解下

發(fā)布時(shí)間:2024/7/19 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 STL源码剖析---红黑树原理详解下 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
轉(zhuǎn)載請標(biāo)明出處,原文地址:http://blog.csdn.net/hackbuteer1/article/details/7760584
? ? ? 算法導(dǎo)論書上給出的紅黑樹的性質(zhì)如下,跟STL源碼剖析書上面的4條性質(zhì)大同小異。
????? 1、每個(gè)結(jié)點(diǎn)或是紅色的,或是黑色的
????? 2、根節(jié)點(diǎn)是黑色的
????? 3、每個(gè)葉結(jié)點(diǎn)(NIL)是黑色的
????? 4、如果一個(gè)節(jié)點(diǎn)是紅色的,則它的兩個(gè)兒子都是黑色的。
????? 5、對于每個(gè)結(jié)點(diǎn),從該結(jié)點(diǎn)到其子孫結(jié)點(diǎn)的所有路徑上包含相同數(shù)目的黑色結(jié)點(diǎn)。

????? 從紅黑樹上刪除一個(gè)節(jié)點(diǎn),可以先用普通二叉搜索樹的方法,將節(jié)點(diǎn)從紅黑樹上刪除掉,然后再將被破壞的紅黑性質(zhì)進(jìn)行恢復(fù)。
????? 我們回憶一下普通二叉樹的節(jié)點(diǎn)刪除方法:Z指向需要刪除的節(jié)點(diǎn),Y指向?qū)嵸|(zhì)結(jié)構(gòu)上被刪除的結(jié)點(diǎn),如果Z節(jié)點(diǎn)只有一個(gè)子節(jié)點(diǎn)或沒有子節(jié)點(diǎn),那么Y就是指向Z指向的節(jié)點(diǎn)。如果Z節(jié)點(diǎn)有兩個(gè)子節(jié)點(diǎn),那么Y指向Z節(jié)點(diǎn)的后繼節(jié)點(diǎn)(其實(shí)前趨也是一樣的),而Z的后繼節(jié)點(diǎn)絕對不可能有左子樹。因此,僅從結(jié)構(gòu)來看,二叉樹上實(shí)質(zhì)被刪除的節(jié)點(diǎn)最多只可能有一個(gè)子樹。
現(xiàn)在我們來看紅黑性質(zhì)的恢復(fù)過程:
????? 如果Y指向的節(jié)點(diǎn)是個(gè)紅色節(jié)點(diǎn),那么直接刪除掉Y以后,紅黑性質(zhì)不會被破壞。操作結(jié)束。
????? 如果Y指向的節(jié)點(diǎn)是個(gè)黑色節(jié)點(diǎn),那么就有幾條紅黑性質(zhì)可能受到破壞了。首先是包含Y節(jié)點(diǎn)的所有路徑,黑高度都減少了一(第5條被破壞)。其次,如果Y的有紅色子節(jié)點(diǎn),Y又有紅色的父節(jié)點(diǎn),那么Y被刪除后,就出現(xiàn)了兩個(gè)相鄰的紅色節(jié)點(diǎn)(第4條被破壞)。最后,如果Y指向的是根節(jié)點(diǎn),而Y的子節(jié)點(diǎn)又是紅色的,那么Y被刪除后,根節(jié)點(diǎn)就變成紅色的了(第2條被破壞)。
????? 其中,第5條被破壞是讓我們比較難受的。因?yàn)檫@影響到了全局。這樣動作就太大太復(fù)雜了。而且在這個(gè)條件下,進(jìn)行其它紅黑性質(zhì)的恢復(fù)也很困難。所以我們首先解決這個(gè)問題:如果不改變含Y路徑的黑高度,那么樹的其它部分的黑高度就必須做出相應(yīng)的變化來適應(yīng)它。所以,我們想辦法恢復(fù)原來含Y節(jié)點(diǎn)的路徑的黑高度。做法就是:無條件的把Y節(jié)點(diǎn)的黑色,推到它的子節(jié)點(diǎn)X上去。(X可能是NIL節(jié)點(diǎn))。這樣,X就可能具有雙重黑色,或同時(shí)具有紅黑兩色,也就是第1條性質(zhì)被破壞了。
????? 但第1條性質(zhì)是比較容易恢復(fù)的:一、如果X是同時(shí)具有紅黑兩色,那么好辦,直接把X涂成黑色,就行了。而且這樣把所有問題都解決了。因?yàn)閷變?yōu)楹谏?#xff0c;2、4兩條如果有問題的話也會得到恢復(fù),算法結(jié)束。二、如果X是雙黑色,那么我們希望把這種情況向上推一直推到根節(jié)點(diǎn)(調(diào)整樹結(jié)構(gòu)和顏色,X的指向新的雙黑色節(jié)點(diǎn),X不斷向上移動),讓根節(jié)點(diǎn)具雙黑色,這時(shí),直接把X的一層黑色去掉就行了(因?yàn)楦?jié)點(diǎn)被包含在所有的路徑上,所以這樣做所有路徑同時(shí)黑高減少一,不會破壞紅黑特征)。
????? 下面就具體地分析如何恢復(fù)1、2、4三個(gè)可能被破壞的紅黑特性:我們知道,如果X指向的節(jié)點(diǎn)是有紅黑兩色,或是X是根節(jié)點(diǎn)時(shí),只需要簡單的對X進(jìn)行一些改變就行了。要對除X節(jié)點(diǎn)外的其它節(jié)點(diǎn)進(jìn)行操作時(shí),必定是這樣的情況:X節(jié)點(diǎn)是雙層黑色,且X有父節(jié)點(diǎn)P。由知可知,X必然有兄弟節(jié)點(diǎn)W,而且這個(gè)W節(jié)點(diǎn)必定有兩個(gè)子節(jié)點(diǎn)。(因?yàn)檫@是原樹滿足紅黑條件要求而自然具備的。X為雙黑色,那么P的另一個(gè)子節(jié)點(diǎn)以下一定要有至少兩層的節(jié)點(diǎn),否則黑色高度不可能和X路徑一致)。所以我們就分析這些節(jié)點(diǎn)之間如何變形,把問題限制在比較小的范圍內(nèi)解決。另一個(gè)前提是:X在一開始,肯定是樹底的葉節(jié)點(diǎn)或是NIL節(jié)點(diǎn),所以在遞歸向上的過程中,每一步都保證下一步進(jìn)行時(shí),至少 X的子樹是滿足紅黑特性的。因此子樹的情況就可以認(rèn)為是已經(jīng)正確的了,這樣,分析就只限制在X節(jié)點(diǎn),X的父節(jié)點(diǎn)P和X的兄弟節(jié)點(diǎn)W,以及W的兩個(gè)子節(jié)點(diǎn)中。
????? 下面僅僅考慮X原本是黑色的情況即可。
????? 在這種情況下,X此時(shí)應(yīng)該具有雙重黑色,算法的過程就是將這多出的一重黑色向上移動,直到遇到紅節(jié)點(diǎn)或者根節(jié)點(diǎn)。
????? 接著往下分析, 會遇到4種情況,實(shí)際上是8種, 因?yàn)槠渲?種是相互對稱的,這可以通過判斷X是其父節(jié)點(diǎn)的右孩子還是左孩子來區(qū)分。下面我們以X是其父節(jié)點(diǎn)的左孩子的情況來分析這4種情況,實(shí)際上接下來的調(diào)整過程,就是要想方設(shè)法將經(jīng)過X的所有路徑上的黑色節(jié)點(diǎn)個(gè)數(shù)增加1。
????? 具體分為以下四種情況:(下面針對x是左兒子的情況討論,右兒子對稱)
????? Case1:X的兄弟W是紅色(想辦法將其變?yōu)楹谏?#xff09;
?????? 由于W是紅色的,因此其兒子節(jié)點(diǎn)和父節(jié)點(diǎn)必為黑色,只要將W和其父節(jié)點(diǎn)的顏色對換,在對
節(jié)點(diǎn)進(jìn)行一次左旋轉(zhuǎn),便將W的左子節(jié)點(diǎn)放到了X的兄弟節(jié)點(diǎn)上,X的兄弟節(jié)點(diǎn)變成了黑色,且紅黑性質(zhì)不變。但還不算完,只是暫時(shí)將情況1轉(zhuǎn)變成了下面的情況2或3或4。

????Case2:X的兄弟節(jié)點(diǎn)W是黑色的,而且W的兩個(gè)子節(jié)點(diǎn)都是黑色的。此時(shí)可以將X的一重黑色和W的黑色同時(shí)去掉,而轉(zhuǎn)加給他們的父節(jié)點(diǎn)上,這是X就指向它的父節(jié)點(diǎn)了,因此此時(shí)父節(jié)點(diǎn)具有雙重顏色了。這一重黑色節(jié)點(diǎn)上移。

????? 如果父節(jié)點(diǎn)原來是紅色的,現(xiàn)在又加一層黑色,那么X現(xiàn)在指向的這個(gè)節(jié)點(diǎn)就是紅黑兩色的,直接把X(也就是父節(jié)點(diǎn))著為黑色。問題就已經(jīng)完整解決了。
???? 如果父節(jié)點(diǎn)現(xiàn)在是雙層黑色,那就以父節(jié)點(diǎn)為新的X進(jìn)行向上的下一次的遞歸。

????Case3:X的兄弟節(jié)點(diǎn)W是黑色的,而且W的左子節(jié)點(diǎn)是紅色的,右子節(jié)點(diǎn)是黑色的。此時(shí)通過交換W和其左子節(jié)點(diǎn)的顏色并進(jìn)行一次向右旋轉(zhuǎn)就可轉(zhuǎn)換成下面的第四種情況。注意,原來L是紅色的,所以L的子節(jié)點(diǎn)一定是黑色的,所以旋轉(zhuǎn)中L節(jié)點(diǎn)的一個(gè)子樹掛到之后著為紅色的W節(jié)點(diǎn)上不會破壞紅黑性質(zhì)。變形后黑色高度不變。

?? ?Case4: X的兄弟節(jié)點(diǎn)W是黑色的,而且W的右子節(jié)點(diǎn)是紅色的。這種情況下,做一次左旋,W就處于根的位置,將W保持為原來的根的位置的顏色,同時(shí)將W的兩個(gè)新的兒子節(jié)點(diǎn)的顏色變?yōu)楹谏?#xff0c;去掉X的一重黑色。這樣 整個(gè)問題也就得到了解決。遞歸結(jié)束。(在代碼上,為了標(biāo)識遞歸結(jié)束,我們把X指向根節(jié)點(diǎn))

????? 因此,只要按上面四種情況一直遞歸處理下去,X最終總會指向根結(jié)點(diǎn)或一個(gè)紅色結(jié)點(diǎn),這時(shí)我們就可以結(jié)束遞歸并把問題解決了。
????? 以上就是紅黑樹的節(jié)點(diǎn)刪除全過程。
????? 總結(jié):
????? 如果我們通過上面的情況畫出所有的分支圖,我們可以得出如下結(jié)論
????? 插入操作:解決的是 紅-紅 問題
????? 刪除操作:解決的是 黑-黑 問題

????? 即你可以從分支圖中看出,需要往上遍歷的情況為紅紅(插入),或者為黑黑黑(刪除)的情況,如果你認(rèn)真分析并總結(jié)所有的情況后,并堅(jiān)持下來,紅黑樹也就沒有想象中的那么恐怖了,并且很美妙;
????? 詳細(xì)的紅黑樹刪除節(jié)點(diǎn)的代碼如下:
#include<iostream> using namespace std;// 定義節(jié)點(diǎn)顏色 ? enum COLOR { ?BLACK = 0, ?RED ? }; ?// 紅黑樹節(jié)點(diǎn) ? typedef struct RB_Tree_Node { ?int key; ?struct RB_Tree_Node *left; ?struct RB_Tree_Node *right; ?struct RB_Tree_Node *parent; ?unsigned char RB_COLOR; ? }RB_Node;// 紅黑樹,包含一個(gè)指向根節(jié)點(diǎn)的指針 ? typedef struct RBTree { ?RB_Node* root; }*RB_Tree;// 紅黑樹的NIL節(jié)點(diǎn) ? static RB_Tree_Node NIL = {0, 0, 0, 0, BLACK}; #define PNIL (&NIL)?? // NIL節(jié)點(diǎn)地址 void Init_RBTree(RB_Tree pTree) // 初始化一棵紅黑樹 ? { ?pTree->root = PNIL; ? }? ?// 查找最小鍵值節(jié)點(diǎn) ? RB_Node* RBTREE_MIN(RB_Node* pRoot) ? { ?while (PNIL != pRoot->left){pRoot = pRoot->left;} ?return pRoot; }/*15/??? \/????? \/??????? \6????????? 18/? \?????? /? \/??? \???? /??? \3????? 7?? 17??? 20/? \???? \/??? \???? \2????? 4???? 13//9 */ // 查找指定節(jié)點(diǎn)的后繼節(jié)點(diǎn) ? RB_Node* RBTREE_SUCCESSOR(RB_Node*? pRoot) ? { ?if (PNIL != pRoot->right)??? // 查找圖中6的后繼節(jié)點(diǎn)時(shí)就調(diào)用RBTREE_MIN函數(shù){ ?return RBTREE_MIN(pRoot->right); ?}// 節(jié)點(diǎn)沒有右子樹的時(shí)候,進(jìn)入下面的while循環(huán)(如查找圖中13的后繼節(jié)點(diǎn)時(shí),它的后繼節(jié)點(diǎn)是15)RB_Node* pParent = pRoot->parent; ?while((PNIL != pParent) && (pRoot == pParent->right)){ ?pRoot = pParent;pParent = pRoot->parent;???? ?}return pParent; }// 紅黑樹的節(jié)點(diǎn)刪除 RB_Node* Delete(RB_Tree pTree , RB_Node* pDel) ? { ?RB_Node* rel_delete_point;if(pDel->left == PNIL || pDel->right == PNIL)rel_delete_point = pDel;elserel_delete_point = RBTREE_SUCCESSOR(pDel);???? // 查找后繼節(jié)點(diǎn)RB_Node* delete_point_child; ?if(rel_delete_point->right != PNIL) ?{ ?delete_point_child = rel_delete_point->right; ?} ?else if(rel_delete_point->left != PNIL) ?{ ?delete_point_child = rel_delete_point->left; ?} ?else ?{ ?delete_point_child = PNIL; ?} ?delete_point_child->parent = rel_delete_point->parent; ?if(rel_delete_point->parent == PNIL)??? // 刪除的節(jié)點(diǎn)是根節(jié)點(diǎn){ ?pTree->root = delete_point_child;} ?else if(rel_delete_point == rel_delete_point->parent->right){ ?rel_delete_point->parent->right = delete_point_child; ?} ?else ?{ ?rel_delete_point->parent->left = delete_point_child; ?}if(pDel != rel_delete_point){pDel->key = rel_delete_point->key;}if(rel_delete_point->RB_COLOR == BLACK) ?{ ?DeleteFixUp(pTree , delete_point_child); ?}return rel_delete_point; ? } ?/* 算法導(dǎo)論上的描述如下: RB-DELETE-FIXUP(T, x) 1 while x ≠ root[T] and color[x] = BLACK 2???? do if x = left[p[x]] 3?????????? then w ← right[p[x]] 4??????????????? if color[w] = RED 5?????????????????? then color[w] ← BLACK?????????????????????????? Case 1 6??????????????????????? color[p[x]] ← RED????????????????????????? Case 1 7??????????????????????? LEFT-ROTATE(T, p[x])?????????????????????? Case 1 8??????????????????????? w ← right[p[x]]??????????????????????????? Case 1 9??????????????? if color[left[w]] = BLACK and color[right[w]] = BLACK 10?????????????????? then color[w] ← RED??????????????????????????? Case 2 11??????????????????????? x p[x]??????????????????????????????????? Case 2 12?????????????????? else if color[right[w]] = BLACK 13?????????????????????????? then color[left[w]] ← BLACK??????????? Case 3 14??????????????????????????????? color[w] ← RED??????????????????? Case 3 15??????????????????????????????? RIGHT-ROTATE(T, w)??????????????? Case 3 16??????????????????????????????? w ← right[p[x]]?????????????????? Case 3 17???????????????????????? color[w] ← color[p[x]]?????????????????? Case 4 18???????????????????????? color[p[x]] ← BLACK????????????????????? Case 4 19???????????????????????? color[right[w]] ← BLACK????????????????? Case 4 20???????????????????????? LEFT-ROTATE(T, p[x])???????????????????? Case 4 21???????????????????????? x ← root[T]????????????????????????????? Case 4 22??????? else (same as then clause with "right" and "left" exchanged) 23 color[x] ← BLACK ? */ ? //接下來的工作,很簡單,即把上述偽代碼改寫成c++代碼即可 ? void DeleteFixUp(RB_Tree pTree , RB_Node* node) ? { ?while(node != pTree->root && node->RB_COLOR == BLACK) ?{ ?if(node == node->parent->left) ?{ ?RB_Node* brother = node->parent->right; ?if(brother->RB_COLOR==RED)?? //情況1:x的兄弟w是紅色的。 ?{ ?brother->RB_COLOR = BLACK; ?node->parent->RB_COLOR = RED; ?RotateLeft(node->parent); ?} ?else???? //情況2:x的兄弟w是黑色的, ?{ ?if(brother->left->RB_COLOR == BLACK && brother->right->RB_COLOR == BLACK)? //w的兩個(gè)孩子都是黑色的 ?{ ?brother->RB_COLOR = RED; ?node = node->parent; ?} ?else{if(brother->right->RB_COLOR == BLACK)?? //情況3:x的兄弟w是黑色的,w的右孩子是黑色(w的左孩子是紅色)。 ?{brother->RB_COLOR = RED;brother->left->RB_COLOR = BLACK;RotateRight(brother);brother = node->parent->right;????? //情況3轉(zhuǎn)換為情況4}//情況4:x的兄弟w是黑色的,且w的右孩子時(shí)紅色的brother->RB_COLOR = node->parent->RB_COLOR; ?node->parent->RB_COLOR = BLACK; ?brother->right->RB_COLOR = BLACK; ?RotateLeft(node->parent); ?node = pTree->root;}//else}//else} ?else?? //同上,原理一致,只是遇到左旋改為右旋,遇到右旋改為左旋即可。其它代碼不變。 ?{ ?RB_Node* brother = node->parent->left; ?if(brother->RB_COLOR == RED) ?{ ?brother->RB_COLOR = BLACK; ?node->parent->RB_COLOR = RED; ?RotateRight(node->parent); ?} ?else ?{ ?if(brother->left->RB_COLOR==BLACK && brother->right->RB_COLOR == BLACK) ?{ ?brother->RB_COLOR = RED; ?node = node->parent; ?} ?else{if(brother->left->RB_COLOR==BLACK) ?{ ?brother->RB_COLOR = RED; ?brother->right->RB_COLOR = BLACK; ?RotateLeft(brother);brother = node->parent->left;????? //情況3轉(zhuǎn)換為情況4}brother->RB_COLOR = node->parent->RB_COLOR; ?node->parent->RB_COLOR = BLACK; ?brother->left->RB_COLOR = BLACK; ?RotateRight(node->parent); ?node = pTree->root; ?} ?} ?} ?}//while node->RB_COLOR = BLACK;??? //如果X節(jié)點(diǎn)原來為紅色,那么直接改為黑色 ? }


轉(zhuǎn)載請標(biāo)明出處,原文地址:http://blog.csdn.net/hackbuteer1/article/details/7760584

與50位技術(shù)專家面對面20年技術(shù)見證,附贈技術(shù)全景圖

總結(jié)

以上是生活随笔為你收集整理的STL源码剖析---红黑树原理详解下的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。