紅黑樹(shù)(二)之 C語(yǔ)言的實(shí)現(xiàn)
?
概要 紅黑樹(shù)在日常的使用中比較常用,例如Java的TreeMap和TreeSet,C++的STL,以及Linux內(nèi)核中都有用到。之前寫(xiě)過(guò)一篇文章專門(mén)介紹紅黑樹(shù)的理論知識(shí) ,本文將給出紅黑數(shù)的C語(yǔ)言的實(shí)現(xiàn)代碼,后序章節(jié)再分別給出C++和Java版本的實(shí)現(xiàn)。還是那句話,三種實(shí)現(xiàn)原理相同,擇其一了解即可;若文章有錯(cuò)誤或不足的地方,望不吝指出!
目錄 1. 紅黑樹(shù)的介紹 2. 紅黑樹(shù)的C實(shí)現(xiàn)(代碼說(shuō)明) 3. 紅黑樹(shù)的C實(shí)現(xiàn)(完整源碼) 4. 紅黑樹(shù)的C測(cè)試程序
轉(zhuǎn)載請(qǐng)注明出處:http://www.cnblogs.com/skywang12345/p/3624177.html
更多內(nèi)容 :數(shù)據(jù)結(jié)構(gòu)與算法系列 目錄
(01)?紅黑樹(shù)(一)之 原理和算法詳細(xì)介紹 (02)?紅黑樹(shù)(二)之 C語(yǔ)言的實(shí)現(xiàn) (03)?紅黑樹(shù)(三)之 Linux內(nèi)核中紅黑樹(shù)的經(jīng)典實(shí)現(xiàn) (04)?紅黑樹(shù)(四)之 C++的實(shí)現(xiàn)? (05)?紅黑樹(shù)(五)之 Java的實(shí)現(xiàn) (06)?紅黑樹(shù)(六)之 參考資料
?
紅黑樹(shù)的介紹 紅黑樹(shù)(Red-Black Tree,簡(jiǎn)稱R-B Tree),它一種特殊的二叉查找樹(shù)。 紅黑樹(shù)是特殊的二叉查找樹(shù),意味著它滿足二叉查找樹(shù)的特征:任意一個(gè)節(jié)點(diǎn)所包含的鍵值,大于等于左孩子的鍵值,小于等于右孩子的鍵值。 除了具備該特性之外,紅黑樹(shù)還包括許多額外的信息。
紅黑樹(shù)的每個(gè)節(jié)點(diǎn)上都有存儲(chǔ)位表示節(jié)點(diǎn)的顏色,顏色是紅(Red)或黑(Black)。 紅黑樹(shù)的特性: (1) 每個(gè)節(jié)點(diǎn)或者是黑色,或者是紅色。 (2) 根節(jié)點(diǎn)是黑色。 (3) 每個(gè)葉子節(jié)點(diǎn)是黑色。 [注意:這里葉子節(jié)點(diǎn),是指為空的葉子節(jié)點(diǎn)!] (4) 如果一個(gè)節(jié)點(diǎn)是紅色的,則它的子節(jié)點(diǎn)必須是黑色的。 (5) 從一個(gè)節(jié)點(diǎn)到該節(jié)點(diǎn)的子孫節(jié)點(diǎn)的所有路徑上包含相同數(shù)目的黑節(jié)點(diǎn)。
關(guān)于它的特性,需要注意的是: 第一,特性(3)中的葉子節(jié)點(diǎn),是只為空(NIL或null)的節(jié)點(diǎn)。 第二,特性(5),確保沒(méi)有一條路徑會(huì)比其他路徑長(zhǎng)出倆倍。因而,紅黑樹(shù)是相對(duì)是接近平衡的二叉樹(shù)。
紅黑樹(shù)示意圖如下:
?
紅黑樹(shù)的C實(shí)現(xiàn)(代碼說(shuō)明) 紅黑樹(shù)的基本操作是添加 、刪除 和旋轉(zhuǎn) 。在對(duì)紅黑樹(shù)進(jìn)行添加或刪除后,會(huì)用到旋轉(zhuǎn)方法。為什么呢?道理很簡(jiǎn)單,添加或刪除紅黑樹(shù)中的節(jié)點(diǎn)之后,紅黑樹(shù)就發(fā)生了變化,可能不滿足紅黑樹(shù)的5條性質(zhì),也就不再是一顆紅黑樹(shù)了,而是一顆普通的樹(shù)。而通過(guò)旋轉(zhuǎn),可以使這顆樹(shù)重新成為紅黑樹(shù)。簡(jiǎn)單點(diǎn)說(shuō),旋轉(zhuǎn)的目的是讓樹(shù)保持紅黑樹(shù)的特性。 旋轉(zhuǎn)包括兩種:左旋 ?和?右旋 。下面分別對(duì)旋轉(zhuǎn)(左旋和右旋)、添加、刪除進(jìn)行介紹。
1. 基本定義
#define RED 0
// 紅色節(jié)點(diǎn)
#define BLACK 1
// 黑色節(jié)點(diǎn) typedef int Type; // 紅黑樹(shù)的節(jié)點(diǎn)
typedef
struct RBTreeNode{unsigned char color;
// 顏色(RED 或 BLACK) Type key;
// 關(guān)鍵字(鍵值) struct RBTreeNode *left;
// 左孩子 struct RBTreeNode *right;
// 右孩子 struct RBTreeNode *parent;
// 父結(jié)點(diǎn)
}Node, *
RBTree; // 紅黑樹(shù)的根
typedef
struct rb_root{Node *
node;
}RBRoot; RBTreeNode是紅黑樹(shù)的節(jié)點(diǎn)類,RBRoot是紅黑樹(shù)的根。
?
2. 左旋
對(duì)x進(jìn)行左旋,意味著"將x變成一個(gè)左節(jié)點(diǎn)"。
左旋的實(shí)現(xiàn)代碼(C語(yǔ)言)
/* * 對(duì)紅黑樹(shù)的節(jié)點(diǎn)(x)進(jìn)行左旋轉(zhuǎn)** 左旋示意圖(對(duì)節(jié)點(diǎn)x進(jìn)行左旋):* px px* / /* x y * / \ --(左旋)--> / \ #* lx y x ry * / \ / \* ly ry lx ly ** */
static void rbtree_left_rotate(RBRoot *root, Node *
x)
{ // 設(shè)置x的右孩子為y Node *y = x->
right; // 將 “y的左孩子” 設(shè)為 “x的右孩子”; // 如果y的左孩子非空,將 “x” 設(shè)為 “y的左孩子的父親” x->right = y->
left; if (y->left !=
NULL)y ->left->parent =
x; // 將 “x的父親” 設(shè)為 “y的父親” y->parent = x->
parent; if (x->parent ==
NULL){ // tree = y; // 如果 “x的父親” 是空節(jié)點(diǎn),則將y設(shè)為根節(jié)點(diǎn) root->node = y;
// 如果 “x的父親” 是空節(jié)點(diǎn),則將y設(shè)為根節(jié)點(diǎn)
} else { if (x->parent->left ==
x)x ->parent->left = y;
// 如果 x是它父節(jié)點(diǎn)的左孩子,則將y設(shè)為“x的父節(jié)點(diǎn)的左孩子” else x ->parent->right = y;
// 如果 x是它父節(jié)點(diǎn)的左孩子,則將y設(shè)為“x的父節(jié)點(diǎn)的左孩子”
} // 將 “x” 設(shè)為 “y的左孩子” y->left =
x; // 將 “x的父節(jié)點(diǎn)” 設(shè)為 “y” x->parent =
y;
} ?
3. 右旋
對(duì)y進(jìn)行左旋,意味著"將y變成一個(gè)右節(jié)點(diǎn)"。
右旋的實(shí)現(xiàn)代碼(C語(yǔ)言)
/* * 對(duì)紅黑樹(shù)的節(jié)點(diǎn)(y)進(jìn)行右旋轉(zhuǎn)** 右旋示意圖(對(duì)節(jié)點(diǎn)y進(jìn)行左旋):* py py* / /* y x * / \ --(右旋)--> / \ #* x ry lx y * / \ / \ #* lx rx rx ry* */
static void rbtree_right_rotate(RBRoot *root, Node *
y)
{ // 設(shè)置x是當(dāng)前節(jié)點(diǎn)的左孩子。 Node *x = y->
left; // 將 “x的右孩子” 設(shè)為 “y的左孩子”; // 如果"x的右孩子"不為空的話,將 “y” 設(shè)為 “x的右孩子的父親” y->left = x->
right; if (x->right !=
NULL)x ->right->parent =
y; // 將 “y的父親” 設(shè)為 “x的父親” x->parent = y->
parent; if (y->parent ==
NULL) { // tree = x; // 如果 “y的父親” 是空節(jié)點(diǎn),則將x設(shè)為根節(jié)點(diǎn) root->node = x;
// 如果 “y的父親” 是空節(jié)點(diǎn),則將x設(shè)為根節(jié)點(diǎn)
} else { if (y == y->parent->
right)y ->parent->right = x;
// 如果 y是它父節(jié)點(diǎn)的右孩子,則將x設(shè)為“y的父節(jié)點(diǎn)的右孩子” else y ->parent->left = x;
// (y是它父節(jié)點(diǎn)的左孩子) 將x設(shè)為“x的父節(jié)點(diǎn)的左孩子”
} // 將 “y” 設(shè)為 “x的右孩子” x->right =
y; // 將 “y的父節(jié)點(diǎn)” 設(shè)為 “x” y->parent =
x;
} ?
4. 添加
將一個(gè)節(jié)點(diǎn)(z)插入到紅黑樹(shù)中,需要執(zhí)行哪些步驟呢?首先,將紅黑樹(shù)當(dāng)作一顆二叉查找樹(shù),將節(jié)點(diǎn)插入;然后,將節(jié)點(diǎn)著色為紅色;最后,通過(guò)"旋轉(zhuǎn)和重新著色"等一系列操作來(lái)修正該樹(shù),使之重新成為一顆紅黑樹(shù)。詳細(xì)描述如下:
第一步: 將紅黑樹(shù)當(dāng)作一顆二叉查找樹(shù),將節(jié)點(diǎn)插入。 ? ? ? ?紅黑樹(shù)本身就是一顆二叉查找樹(shù),將節(jié)點(diǎn)插入后,該樹(shù)仍然是一顆二叉查找樹(shù)。也就意味著,樹(shù)的鍵值仍然是有序的。此外,無(wú)論是左旋還是右旋,若旋轉(zhuǎn)之前這棵樹(shù)是二叉查找樹(shù),旋轉(zhuǎn)之后它一定還是二叉查找樹(shù)。這也就意味著,任何的旋轉(zhuǎn)和重新著色操作,都不會(huì)改變它仍然是一顆二叉查找樹(shù)的事實(shí)。 ? ? ? ?好吧?那接下來(lái),我們就來(lái)想方設(shè)法的旋轉(zhuǎn)以及重新著色,使這顆樹(shù)重新成為紅黑樹(shù)!
第二步:將插入的節(jié)點(diǎn)著色為"紅色"。 ? ? ? ?為什么著色成紅色,而不是黑色呢?為什么呢?在回答之前,我們需要重新溫習(xí)一下紅黑樹(shù)的特性: (1) 每個(gè)節(jié)點(diǎn)或者是黑色,或者是紅色。 (2) 根節(jié)點(diǎn)是黑色。 (3) 每個(gè)葉子節(jié)點(diǎn)是黑色。 [注意:這里葉子節(jié)點(diǎn),是指為空的葉子節(jié)點(diǎn)!] (4) 如果一個(gè)節(jié)點(diǎn)是紅色的,則它的子節(jié)點(diǎn)必須是黑色的。 (5) 從一個(gè)節(jié)點(diǎn)到該節(jié)點(diǎn)的子孫節(jié)點(diǎn)的所有路徑上包含相同數(shù)目的黑節(jié)點(diǎn)。 ? ? ? ?將插入的節(jié)點(diǎn)著色為紅色,不會(huì)違背"特性(5)"!少違背一條特性,就意味著我們需要處理的情況越少。接下來(lái),就要努力的讓這棵樹(shù)滿足其它性質(zhì)即可;滿足了的話,它就又是一顆紅黑樹(shù)了。o(∩∩)o...哈哈
第三步: 通過(guò)一系列的旋轉(zhuǎn)或著色等操作,使之重新成為一顆紅黑樹(shù)。 ? ? ? ?第二步中,將插入節(jié)點(diǎn)著色為"紅色"之后,不會(huì)違背"特性(5)"。那它到底會(huì)違背哪些特性呢? ? ? ? ?對(duì)于"特性(1)",顯然不會(huì)違背了。因?yàn)槲覀円呀?jīng)將它涂成紅色了。 ? ? ? ?對(duì)于"特性(2)",顯然也不會(huì)違背。在第一步中,我們是將紅黑樹(shù)當(dāng)作二叉查找樹(shù),然后執(zhí)行的插入操作。而根據(jù)二叉查找數(shù)的特點(diǎn),插入操作不會(huì)改變根節(jié)點(diǎn)。所以,根節(jié)點(diǎn)仍然是黑色。 ? ? ? ?對(duì)于"特性(3)",顯然不會(huì)違背了。這里的葉子節(jié)點(diǎn)是指的空葉子節(jié)點(diǎn),插入非空節(jié)點(diǎn)并不會(huì)對(duì)它們?cè)斐捎绊憽?/span> ? ? ? ?對(duì)于"特性(4)",是有可能違背的! 那接下來(lái),想辦法使之"滿足特性(4)",就可以將樹(shù)重新構(gòu)造成紅黑樹(shù)了。
添加操作的實(shí)現(xiàn)代碼(C語(yǔ)言)
/* * 添加節(jié)點(diǎn):將節(jié)點(diǎn)(node)插入到紅黑樹(shù)中** 參數(shù)說(shuō)明:* root 紅黑樹(shù)的根* node 插入的結(jié)點(diǎn) // 對(duì)應(yīng)《算法導(dǎo)論》中的z */
static void rbtree_insert(RBRoot *root, Node *
node)
{Node *y =
NULL;Node *x = root->
node; // 1. 將紅黑樹(shù)當(dāng)作一顆二叉查找樹(shù),將節(jié)點(diǎn)添加到二叉查找樹(shù)中。 while (x !=
NULL){y =
x; if (node->key < x->
key)x = x->
left; else x = x->
right;}rb_parent(node) =
y; if (y !=
NULL){ if (node->key < y->
key)y ->left = node;
// 情況2:若“node所包含的值” < “y所包含的值”,則將node設(shè)為“y的左孩子” else y ->right = node;
// 情況3:(“node所包含的值” >= “y所包含的值”)將node設(shè)為“y的右孩子”
} else {root ->node = node;
// 情況1:若y是空節(jié)點(diǎn),則將node設(shè)為根
} // 2. 設(shè)置節(jié)點(diǎn)的顏色為紅色 node->color =
RED; // 3. 將它重新修正為一顆二叉查找樹(shù)
rbtree_insert_fixup(root, node);
} rbtree_insert(root, node)的作用是將"node"節(jié)點(diǎn)插入到紅黑樹(shù)中。其中,root是根,node是被插入節(jié)點(diǎn)。 rbtree_insert(root, node)是參考《算法導(dǎo)論》中紅黑樹(shù)的插入函數(shù)的偽代碼進(jìn)行實(shí)現(xiàn)的。
添加修正操作的實(shí)現(xiàn)代碼(C語(yǔ)言)
/* * 紅黑樹(shù)插入修正函數(shù)** 在向紅黑樹(shù)中插入節(jié)點(diǎn)之后(失去平衡),再調(diào)用該函數(shù);* 目的是將它重新塑造成一顆紅黑樹(shù)。** 參數(shù)說(shuō)明:* root 紅黑樹(shù)的根* node 插入的結(jié)點(diǎn) // 對(duì)應(yīng)《算法導(dǎo)論》中的z */
static void rbtree_insert_fixup(RBRoot *root, Node *
node)
{Node *parent, *
gparent; // 若“父節(jié)點(diǎn)存在,并且父節(jié)點(diǎn)的顏色是紅色” while ((parent = rb_parent(node)) &&
rb_is_red(parent)){gparent =
rb_parent(parent); // 若“父節(jié)點(diǎn)”是“祖父節(jié)點(diǎn)的左孩子” if (parent == gparent->
left){ // Case 1條件:叔叔節(jié)點(diǎn)是紅色
{Node *uncle = gparent->
right; if (uncle &&
rb_is_red(uncle)){rb_set_black(uncle);rb_set_black(parent);rb_set_red(gparent);node =
gparent; continue ;}} // Case 2條件:叔叔是黑色,且當(dāng)前節(jié)點(diǎn)是右孩子 if (parent->right ==
node){Node *
tmp;rbtree_left_rotate(root, parent);tmp =
parent;parent =
node;node =
tmp;} // Case 3條件:叔叔是黑色,且當(dāng)前節(jié)點(diǎn)是左孩子。
rb_set_black(parent);rb_set_red(gparent);rbtree_right_rotate(root, gparent);} else // 若“z的父節(jié)點(diǎn)”是“z的祖父節(jié)點(diǎn)的右孩子”
{ // Case 1條件:叔叔節(jié)點(diǎn)是紅色
{Node *uncle = gparent->
left; if (uncle &&
rb_is_red(uncle)){rb_set_black(uncle);rb_set_black(parent);rb_set_red(gparent);node =
gparent; continue ;}} // Case 2條件:叔叔是黑色,且當(dāng)前節(jié)點(diǎn)是左孩子 if (parent->left ==
node){Node *
tmp;rbtree_right_rotate(root, parent);tmp =
parent;parent =
node;node =
tmp;} // Case 3條件:叔叔是黑色,且當(dāng)前節(jié)點(diǎn)是右孩子。
rb_set_black(parent);rb_set_red(gparent);rbtree_left_rotate(root, gparent);}} // 將根節(jié)點(diǎn)設(shè)為黑色 rb_set_black(root->
node);
} rbtree_insert_fixup(root, node)的作用是對(duì)應(yīng)"上面所講的第三步"。
?
5. 刪除操作
將紅黑樹(shù)內(nèi)的某一個(gè)節(jié)點(diǎn)刪除。需要執(zhí)行的操作依次是:首先,將紅黑樹(shù)當(dāng)作一顆二叉查找樹(shù),將該節(jié)點(diǎn)從二叉查找樹(shù)中刪除;然后,通過(guò)"旋轉(zhuǎn)和重新著色"等一系列來(lái)修正該樹(shù),使之重新成為一棵紅黑樹(shù)。詳細(xì)描述如下:
第一步:將紅黑樹(shù)當(dāng)作一顆二叉查找樹(shù),將節(jié)點(diǎn)刪除。 ? ? ? ?這和"刪除常規(guī)二叉查找樹(shù)中刪除節(jié)點(diǎn)的方法是一樣的"。分3種情況: ① 被刪除節(jié)點(diǎn)沒(méi)有兒子,即為葉節(jié)點(diǎn)。那么,直接將該節(jié)點(diǎn)刪除就OK了。 ② 被刪除節(jié)點(diǎn)只有一個(gè)兒子。那么,直接刪除該節(jié)點(diǎn),并用該節(jié)點(diǎn)的唯一子節(jié)點(diǎn)頂替它的位置。 ③ 被刪除節(jié)點(diǎn)有兩個(gè)兒子。那么,先找出它的后繼節(jié)點(diǎn);然后把“它的后繼節(jié)點(diǎn)的內(nèi)容”復(fù)制給“該節(jié)點(diǎn)的內(nèi)容”;之后,刪除“它的后繼節(jié)點(diǎn)”。在這里,后繼節(jié)點(diǎn)相當(dāng)于替身,在將后繼節(jié)點(diǎn)的內(nèi)容復(fù)制給"被刪除節(jié)點(diǎn)"之后,再將后繼節(jié)點(diǎn)刪除。這樣就巧妙的將問(wèn)題轉(zhuǎn)換為"刪除后繼節(jié)點(diǎn)"的情況了,下面就考慮后繼節(jié)點(diǎn)。 在"被刪除節(jié)點(diǎn)"有兩個(gè)非空子節(jié)點(diǎn)的情況下,它的后繼節(jié)點(diǎn)不可能是雙子非空。既然"的后繼節(jié)點(diǎn)"不可能雙子都非空,就意味著"該節(jié)點(diǎn)的后繼節(jié)點(diǎn)"要么沒(méi)有兒子,要么只有一個(gè)兒子。若沒(méi)有兒子,則按"情況① "進(jìn)行處理;若只有一個(gè)兒子,則按"情況② "進(jìn)行處理。
第二步:通過(guò)"旋轉(zhuǎn)和重新著色"等一系列來(lái)修正該樹(shù),使之重新成為一棵紅黑樹(shù)。 因?yàn)?#34;第一步"中刪除節(jié)點(diǎn)之后,可能會(huì)違背紅黑樹(shù)的特性。所以需要通過(guò)"旋轉(zhuǎn)和重新著色"來(lái)修正該樹(shù),使之重新成為一棵紅黑樹(shù)。
刪除操作的實(shí)現(xiàn)代碼(C語(yǔ)言)
/* * 刪除結(jié)點(diǎn)** 參數(shù)說(shuō)明:* tree 紅黑樹(shù)的根結(jié)點(diǎn)* node 刪除的結(jié)點(diǎn) */
void rbtree_delete(RBRoot *root, Node *
node)
{Node *child, *
parent; int color; // 被刪除節(jié)點(diǎn)的"左右孩子都不為空"的情況。 if ( (node->left!=NULL) && (node->right!=
NULL) ) { // 被刪節(jié)點(diǎn)的后繼節(jié)點(diǎn)。(稱為"取代節(jié)點(diǎn)") // 用它來(lái)取代"被刪節(jié)點(diǎn)"的位置,然后再將"被刪節(jié)點(diǎn)"去掉。 Node *replace =
node; // 獲取后繼節(jié)點(diǎn) replace = replace->
right; while (replace->left !=
NULL)replace = replace->
left; // "node節(jié)點(diǎn)"不是根節(jié)點(diǎn)(只有根節(jié)點(diǎn)不存在父節(jié)點(diǎn)) if (rb_parent(node)){ if (rb_parent(node)->left ==
node)rb_parent(node) ->left =
replace; else rb_parent(node) ->right =
replace;} else // "node節(jié)點(diǎn)"是根節(jié)點(diǎn),更新根節(jié)點(diǎn)。 root->node =
replace; // child是"取代節(jié)點(diǎn)"的右孩子,也是需要"調(diào)整的節(jié)點(diǎn)"。 // "取代節(jié)點(diǎn)"肯定不存在左孩子!因?yàn)樗且粋€(gè)后繼節(jié)點(diǎn)。 child = replace->
right;parent =
rb_parent(replace); // 保存"取代節(jié)點(diǎn)"的顏色 color =
rb_color(replace); // "被刪除節(jié)點(diǎn)"是"它的后繼節(jié)點(diǎn)的父節(jié)點(diǎn)" if (parent ==
node){parent =
replace;} else { // child不為空 if (child)rb_set_parent(child, parent);parent ->left =
child;replace ->right = node->
right;rb_set_parent(node ->
right, replace);}replace ->parent = node->
parent;replace ->color = node->
color;replace ->left = node->
left;node ->left->parent =
replace; if (color ==
BLACK)rbtree_delete_fixup(root, child, parent);free(node); return ;} if (node->left !=
NULL)child = node->
left; else child = node->
right;parent = node->
parent; // 保存"取代節(jié)點(diǎn)"的顏色 color = node->
color; if (child)child ->parent =
parent; // "node節(jié)點(diǎn)"不是根節(jié)點(diǎn) if (parent){ if (parent->left ==
node)parent ->left =
child; else parent ->right =
child;} else root ->node =
child; if (color ==
BLACK)rbtree_delete_fixup(root, child, parent);free(node);
} rbtree_delete(root, node)的作用是將"node"節(jié)點(diǎn)插入到紅黑樹(shù)中。其中,root是根,node是被插入節(jié)點(diǎn)。
刪除修正操作的實(shí)現(xiàn)代碼(C語(yǔ)言)
/* * 紅黑樹(shù)刪除修正函數(shù)** 在從紅黑樹(shù)中刪除插入節(jié)點(diǎn)之后(紅黑樹(shù)失去平衡),再調(diào)用該函數(shù);* 目的是將它重新塑造成一顆紅黑樹(shù)。** 參數(shù)說(shuō)明:* root 紅黑樹(shù)的根* node 待修正的節(jié)點(diǎn) */
static void rbtree_delete_fixup(RBRoot *root, Node *node, Node *
parent)
{Node *
other; while ((!node || rb_is_black(node)) && node != root->
node){ if (parent->left ==
node){other = parent->
right; if (rb_is_red(other)){ // Case 1: x的兄弟w是紅色的
rb_set_black(other);rb_set_red(parent);rbtree_left_rotate(root, parent);other = parent->
right;} if ((!other->left || rb_is_black(other->left)) &&
( !other->right || rb_is_black(other->
right))){ // Case 2: x的兄弟w是黑色,且w的倆個(gè)孩子也都是黑色的
rb_set_red(other);node =
parent;parent =
rb_parent(node);} else { if (!other->right || rb_is_black(other->
right)){ // Case 3: x的兄弟w是黑色的,并且w的左孩子是紅色,右孩子為黑色。 rb_set_black(other->
left);rb_set_red(other);rbtree_right_rotate(root, other);other = parent->
right;} // Case 4: x的兄弟w是黑色的;并且w的右孩子是紅色的,左孩子任意顏色。
rb_set_color(other, rb_color(parent));rb_set_black(parent);rb_set_black(other ->
right);rbtree_left_rotate(root, parent);node = root->
node; break ;}} else {other = parent->
left; if (rb_is_red(other)){ // Case 1: x的兄弟w是紅色的
rb_set_black(other);rb_set_red(parent);rbtree_right_rotate(root, parent);other = parent->
left;} if ((!other->left || rb_is_black(other->left)) &&
( !other->right || rb_is_black(other->
right))){ // Case 2: x的兄弟w是黑色,且w的倆個(gè)孩子也都是黑色的
rb_set_red(other);node =
parent;parent =
rb_parent(node);} else { if (!other->left || rb_is_black(other->
left)){ // Case 3: x的兄弟w是黑色的,并且w的左孩子是紅色,右孩子為黑色。 rb_set_black(other->
right);rb_set_red(other);rbtree_left_rotate(root, other);other = parent->
left;} // Case 4: x的兄弟w是黑色的;并且w的右孩子是紅色的,左孩子任意顏色。
rb_set_color(other, rb_color(parent));rb_set_black(parent);rb_set_black(other ->
left);rbtree_right_rotate(root, parent);node = root->
node; break ;}}} if (node)rb_set_black(node);
} rbtree_delete_fixup(root, node, parent)是對(duì)應(yīng)"上面所講的第三步"。
?
紅黑樹(shù)的C實(shí)現(xiàn)(完整源碼) 下面是紅黑數(shù)實(shí)現(xiàn)的完整代碼和相應(yīng)的測(cè)試程序。 (1) 除了上面所說(shuō)的"左旋"、"右旋"、"添加"、"刪除"等基本操作之后,還實(shí)現(xiàn)了"遍歷"、"查找"、"打印"、"最小值"、"最大值"、"創(chuàng)建"、"銷毀"等接口。 (2) 函數(shù)接口分為內(nèi)部接口和外部接口。內(nèi)部接口是static函數(shù),外部接口則是非static函數(shù),外部接口都在.h頭文件中表明了。 (3) 測(cè)試代碼中提供了"插入"和"刪除"動(dòng)作的檢測(cè)開(kāi)關(guān)。默認(rèn)是關(guān)閉的,打開(kāi)方法可以參考"代碼中的說(shuō)明"。建議在打開(kāi)開(kāi)關(guān)后,在草稿上自己動(dòng)手繪制一下紅黑樹(shù)。
紅黑樹(shù)的實(shí)現(xiàn)文件(rbtree.h)
?
View Code 紅黑樹(shù)的實(shí)現(xiàn)文件(rbtree.c)
?
View Code 紅黑樹(shù)的測(cè)試文件(rbtree_test.c)
?
View Code ?
紅黑樹(shù)的C測(cè)試程序 前面已經(jīng)給出了紅黑樹(shù)的測(cè)試程序(rbtree_test.c),這里就不再重復(fù)說(shuō)明。下面是測(cè)試程序的運(yùn)行結(jié)果:
== 原始數(shù)據(jù): 10 40 30 60 90 70 20 50 80
== 前序遍歷: 30 10 20 60 40 50 80 70 90
== 中序遍歷: 10 20 30 40 50 60 70 80 90
== 后序遍歷: 20 10 50 40 70 90 80 60 30
== 最小值: 10
== 最大值: 90
==
樹(shù)的詳細(xì)信息:
30
(B) is root
10(B) is 30's left child
20(R) is 10's right child
60(R) is 30's right child
40(B) is 60's left child
50(R) is 40's right child
80(B) is 60's right child
70(R) is 80's left child
90(R) is 80's right child
總結(jié)
以上是生活随笔 為你收集整理的红黑树(二)之 C语言的实现 的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔 網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔 推薦給好友。