樹(shù)算法之紅黑樹(shù)
羅朝輝(http://www.shnenglu.com/kesalin)
轉(zhuǎn)載請(qǐng)注明出處
紅黑樹(shù)本質(zhì)是二叉查找樹(shù)的一種,它的性能高于普通的二叉查找樹(shù),即使是在最壞的情況下也能保證時(shí)間復(fù)雜度為O(lgn)。紅黑樹(shù)在每個(gè)結(jié)點(diǎn)上增加一個(gè)存儲(chǔ)位表示結(jié)點(diǎn)的顏色(或紅或黑,故稱紅黑樹(shù))。通過(guò)對(duì)任何一條從根到葉子的路徑上各個(gè)結(jié)點(diǎn)著色方式的限制,紅黑樹(shù)可以保證沒(méi)有一條路徑會(huì)比其他路徑長(zhǎng)出兩倍,因而是接近平衡的。
紅黑樹(shù)的每個(gè)結(jié)點(diǎn)至少包含五個(gè)域:color,key,left,right 和 parent(一般我們都會(huì)在結(jié)點(diǎn)中存儲(chǔ)額外的數(shù)據(jù) data,但前面的五個(gè)域是必不可少的),如果某個(gè)結(jié)點(diǎn)沒(méi)有子結(jié)點(diǎn)或者
結(jié)節(jié)點(diǎn),則將相應(yīng)的指針設(shè)置為空值(NIL,注意不是 NULL,NIL是一個(gè)特定的空結(jié)點(diǎn)對(duì)象,類似于Obj-C 中 Nil對(duì)象)。我們將這些 NIL 當(dāng)作葉子
結(jié)點(diǎn)(在實(shí)際處理過(guò)程中,往往將最底層的孩子
結(jié)點(diǎn)和根
結(jié)點(diǎn)的父親都指向同一個(gè) NIL
結(jié)點(diǎn),
以便于處理紅黑樹(shù)代碼中的邊界條件),而將其它
結(jié)點(diǎn)當(dāng)作內(nèi)結(jié)點(diǎn)。
滿足如下 5 個(gè)性質(zhì)的二叉樹(shù)就是一顆紅黑樹(shù):
一,每個(gè)結(jié)點(diǎn)只有一種顏色,或紅色或黑色;
二,根結(jié)點(diǎn)是黑色的;
三,每個(gè)葉結(jié)點(diǎn)是黑色的;
四,如果一個(gè)結(jié)點(diǎn)是紅色的,那么它的兩個(gè)孩子結(jié)點(diǎn)必須是黑色的;
五,對(duì)每個(gè)結(jié)點(diǎn),從該結(jié)點(diǎn)到其子孫結(jié)點(diǎn)的所有路徑上包含相同數(shù)目 H 的黑色結(jié)點(diǎn), H 即為該節(jié)點(diǎn)的高度。
紅黑樹(shù)的實(shí)現(xiàn),
linux 內(nèi)核中有現(xiàn)成實(shí)現(xiàn)算法,園子里也有不少同學(xué)(
那誰(shuí) 等)實(shí)現(xiàn)過(guò)。在這里我重復(fù)制造一下輪子,當(dāng)然我這里的實(shí)現(xiàn)與前面提到的有些不同,這里是按照《算法導(dǎo)論》上的算法描述實(shí)現(xiàn)的。
具體算法過(guò)程,請(qǐng)參考《算法導(dǎo)論》中紅黑樹(shù)那一章。
下面先來(lái)看
看頭文件中包含的數(shù)據(jù)結(jié)構(gòu),接口函數(shù):
#ifndef __RED_BLACK_TREE_H__
#define __RED_BLACK_TREE_H__


enum RBColor
{
RB_Red,
RB_Black,
};

struct RBNode


{
RBColor color;
int key;
RBNode* leftChild;
RBNode* rightChild;
RBNode* parent;
};

typedef RBNode* RBTree;

RBNode* RBTree_nil();

// 最小關(guān)鍵字元素
RBNode* RBTree_minimum(RBNode* node);

// 最大關(guān)鍵字元素
RBNode* RBTree_maximum(RBNode* node);

// 中序遍歷中的前驅(qū)
RBNode* RBTree_predecessor(RBNode* node);

// 中序遍歷中的后繼
RBNode* RBTree_successor(RBNode* node);

void RBTree_insert(RBTree* tree, RBNode* node);

RBNode* RBTree_delete(RBTree* tree, RBNode* node);

RBNode* RBTree_search(const RBTree tree, int key);

void RBTree_print(RBTree tree, int her = 1);

#endif // __RED_BLACK_TREE_H__
下面來(lái)看具體實(shí)現(xiàn):
#include "RedBlackTree.h"
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>


static RBNode RBNode_Nil =
{RB_Black, 0, 0, 0, 0};

RBNode* RBTree_nil()


{
return &RBNode_Nil;
}

void RBTree_print(RBTree tree, int her)


{
int i;
RBNode* node = tree;

assert(node);


if (node != &RBNode_Nil)
{

for (i = 0; i < her; i++)
{
printf(" ");
}
printf("第 %d 層, %d(%c)\n",
her, node->key, node->color == RB_Black ? 'B' : 'R');


if (node->leftChild != &RBNode_Nil)
{
RBTree_print(node->leftChild, her + 1);
}


if (node->rightChild != &RBNode_Nil)
{
RBTree_print(node->rightChild, her + 1);
}
}
}

// 最小關(guān)鍵字元素
RBNode* RBTree_minimum(RBNode* node)


{
assert(node);

RBNode* temp = node;

while (temp->leftChild != &RBNode_Nil)
{
temp = temp->leftChild;
}

return temp;
}


// 最大關(guān)鍵字元素
RBNode* RBTree_maximum(RBNode* node)


{
assert(node);

RBNode* temp = node;

while (temp->rightChild != &RBNode_Nil)
{
temp = temp->rightChild;
}

return temp;
}

// 中序遍歷中的前驅(qū)
RBNode* RBTree_predecessor(RBNode* node)


{
assert(node);

RBNode* child = node->leftChild;

// 沒(méi)有左孩子,返回自身

if (child == &RBNode_Nil)
{
return node;
}

// 只有左孩子,則左孩子是其直接前驅(qū)

else if (child->rightChild == &RBNode_Nil)
{
return child->leftChild;
}

// 左右孩子均有,則右孩子樹(shù)中最大的元素為其直接前驅(qū)

else
{
return RBTree_maximum(child->rightChild);
}
}

// 中序遍歷中的后繼
RBNode* RBTree_successor(RBNode* node)


{
// 有右孩子,則右孩子樹(shù)中最小的元素為其直接后繼

if (node->rightChild != &RBNode_Nil)
{
return RBTree_minimum(node->rightChild);
}

// 沒(méi)有右孩子,向上找到的第一個(gè)左分支節(jié)點(diǎn)為其直接后繼,
// 即 node 為其直接后繼的左孩子樹(shù)中的最大元素。
RBNode* temp = node;
RBNode* parent = temp->parent;


while (parent != &RBNode_Nil && temp == parent->rightChild)
{
temp = parent;
parent = temp->parent;
}

return parent;
}

RBNode* RBTree_search(const RBTree tree, int key)


{
RBNode* node = tree;


while (node != &RBNode_Nil)
{

if (node->key == key)
{
return node;
}


else if (node->key < key)
{
node = node->rightChild;
}

else
{
node = node->leftChild;
}
}

return &RBNode_Nil;
}

// 左旋
// node right
// / \ / \
// a right --> node c
// / \ / \
// b c a b
//
void RBTree_left_rotate(RBTree* tree, RBNode* node)


{
assert(node->rightChild && (*tree)->parent == &RBNode_Nil);

RBNode* right = node->rightChild;

// set b
node->rightChild = right->leftChild;

if (right->leftChild != &RBNode_Nil)
{
right->leftChild->parent = node;
}

right->parent = node->parent;

if (node->parent == &RBNode_Nil)
{
*tree = right;
}

else if (node->parent->leftChild == node)
{
node->parent->leftChild = right;
}

else
{
node->parent->rightChild = right;
}

right->leftChild = node;
node->parent = right;
}

// 右旋
// node left
// / \ / \
// left c --> a node
// / \ / \
// a b b c
//
void RBTree_right_rotate(RBTree* tree, RBNode* node)


{
assert(node->leftChild && (*tree)->parent == &RBNode_Nil);

RBNode* left = node->leftChild;

// set b
node->leftChild = left->rightChild;

if (left->rightChild != &RBNode_Nil)
{
left->rightChild->parent = node;
}

left->parent = node->parent;

if (node->parent == &RBNode_Nil)
{
*tree = left;
}

else if (node->parent->leftChild == node)
{
node->parent->leftChild = left;
}

else
{
node->parent->rightChild = left;
}

left->rightChild = node;
node->parent = left;
}

// 插入調(diào)整
void RBTree_insert_fixup(RBTree* tree, RBNode* node)


{
assert(tree && node);

RBNode* parent = NULL;
RBNode* uncle = NULL;
RBNode* grand = NULL;
RBNode* temp = NULL;

parent = node->parent;

while (parent->color == RB_Red)
{
// 根據(jù)紅黑樹(shù)性質(zhì),以及 node 的父親的顏色為紅色,
// 可以肯定 node 的祖父節(jié)點(diǎn)一定存在
grand = parent->parent;

// 確定叔父節(jié)點(diǎn)

if (parent == grand->leftChild)
{
uncle = grand->rightChild;

// case 1: 叔父節(jié)點(diǎn)為紅色
// grand(B) new node -> grand(R)
// / \ / \
// parent(R) uncle(R) --> node(B) uncle(B)
// / \ / \ / \ / \
// a node(R) d e parent node(R) d e
// / \ / \
// b c b c
//

if (uncle->color == RB_Red)
{
parent->color = RB_Black;
uncle->color = RB_Black;
grand->color = RB_Red;
node = grand;
parent = node->parent;
}

// case 2, case 3:叔父節(jié)點(diǎn)為黑色
// case 2 ---> case 3 --> done
// parent is as new node
// grand(B) grand(B) node(B)
// / \ / \ / \
// parent(R) d node(R) d parent(R) grand(R)
// / \ / \ / \ / \
// a node(R) parent(R) c a b c d
// / \ / \
// b c a b
//

else
{
// 將 case 2 裝換成 case 3

if (parent->rightChild == node)
{
RBTree_left_rotate(tree, parent);
temp = parent;
parent = node;
node = temp;
}

// case 3
parent->color = RB_Black;
grand->color = RB_Red;

RBTree_right_rotate(tree, grand);
}
}

else
{
// 與上面的情況對(duì)稱
uncle = grand->leftChild;


if (uncle->color == RB_Red)
{
parent->color = RB_Black;
uncle->color = RB_Black;
grand->color = RB_Red;
node = grand;
parent = node->parent;
}


else
{
// 將 case 2 裝換成 case 3

if (parent->leftChild == node)
{
RBTree_right_rotate(tree, parent);
temp = parent;
parent = node;
node = temp;
}

// case 3
parent->color = RB_Black;
grand->color = RB_Red;

RBTree_left_rotate(tree, grand);
}
}
}

(*tree)->color = RB_Black;
}

// 將節(jié)點(diǎn) node 插入樹(shù) tree 內(nèi),然后將 node 著色為紅色,此時(shí),樹(shù)可能不再
// 滿足紅黑樹(shù)性質(zhì),因此調(diào)用 RBTree_insert_fixup 來(lái)對(duì)節(jié)點(diǎn)重新著色調(diào)整。
void RBTree_insert(RBTree* tree, RBNode* node)


{
assert(tree && node);

RBNode* parent = &RBNode_Nil;
RBNode* temp = *tree;

// 像二叉樹(shù)一樣,在樹(shù)中查找適當(dāng)?shù)奈恢貌迦?/span>

while (temp != &RBNode_Nil)
{
parent = temp;


if (node->key < temp->key)
{
temp = temp->leftChild;
}

else
{
temp = temp->rightChild;
}
}

node->parent = parent;

// 樹(shù)為空

if (parent == &RBNode_Nil)
{
*tree = node;
}

else if (node->key < parent->key)
{
parent->leftChild = node;
}

else
{
parent->rightChild = node;
}

// 為節(jié)點(diǎn)著色
node->leftChild = &RBNode_Nil;
node->rightChild = &RBNode_Nil;
node->color = RB_Red;

// 調(diào)整樹(shù)使之滿足紅黑樹(shù)性質(zhì)
RBTree_insert_fixup(tree, node);
}

// 刪除調(diào)整
void RBTree_delete_fixup(RBTree* tree, RBNode* node)


{
RBNode* brother = NULL;
RBNode* parent = NULL;


while (node != *tree && node->color == RB_Black)
{
parent = node->parent;

// 確定兄弟節(jié)點(diǎn)

if (node == parent->leftChild)
{
brother = parent->rightChild;

// case 1: 兄弟節(jié)點(diǎn)為紅色

if (brother->color == RB_Red)
{
brother->color = RB_Black;
parent->color = RB_Red;

RBTree_left_rotate(tree, parent);

brother = node->parent->rightChild;
}

// case 2: 兄弟節(jié)點(diǎn)的兩孩子均為黑色
if (brother->leftChild->color == RB_Black

&& brother->rightChild->color == RB_Black)
{
brother->color = RB_Red;
node = parent;
}


else
{
// case 3: 兄弟節(jié)點(diǎn)的左孩子為紅色,右孩子為黑色

if (brother->rightChild->color == RB_Black)
{
brother->leftChild->color = RB_Black;
brother->color = RB_Red;

RBTree_right_rotate(tree, brother);

brother = node->parent->rightChild;
}

// case 4:兄弟節(jié)點(diǎn)的右孩子為紅色
brother->color = parent->color;
parent->color = RB_Black;
brother->rightChild->color = RB_Black;

RBTree_left_rotate(tree, parent);

node = *tree;
}
}

else
{
brother = node->parent->leftChild;

// case 1: 兄弟節(jié)點(diǎn)為紅色

if (brother->color == RB_Red)
{
brother->color = RB_Black;
parent->color = RB_Red;

RBTree_right_rotate(tree, parent);

brother = node->parent->leftChild;
}

// case 2: 兄弟節(jié)點(diǎn)的兩孩子均為黑色
if (brother->leftChild->color == RB_Black

&& brother->rightChild->color == RB_Black)
{
brother->color = RB_Red;
node = parent;
}


else
{
// case 3: 兄弟節(jié)點(diǎn)的左孩子為紅色,右孩子為黑色

if (brother->rightChild->color == RB_Black)
{
brother->leftChild->color = RB_Black;
brother->color = RB_Red;

RBTree_left_rotate(tree, brother);

brother = node->parent->rightChild;
}

// case 4:兄弟節(jié)點(diǎn)的右孩子為紅色
brother->color = parent->color;
parent->color = RB_Black;
brother->leftChild->color = RB_Black;

RBTree_right_rotate(tree, parent);

node = *tree;
}
}
}

node->color = RB_Black;
}

// 刪除
RBNode* RBTree_delete(RBTree* tree, RBNode* node)


{
RBNode* successor = NULL;
RBNode* temp = NULL;


if (node->leftChild == &RBNode_Nil || node->rightChild == &RBNode_Nil)
{
successor = node;
}

else
{
successor = RBTree_successor(node);
}


if (successor->leftChild != &RBNode_Nil)
{
temp = successor->leftChild;
}

else
{
temp = successor->rightChild;
}

temp->parent = successor->parent;


if (successor->parent == &RBNode_Nil)
{
*tree = temp;
}

else
{

if (successor == successor->parent->leftChild)
{
successor->parent->leftChild = temp;
}

else
{
successor->parent->rightChild = temp;
}
}


if (successor != node)
{
node->key = successor->key;
}


if (successor->color == RB_Black)
{
RBTree_delete_fixup(tree, temp);
}

return successor;
}
測(cè)試代碼,測(cè)試數(shù)組中的數(shù)字與測(cè)試步驟是經(jīng)過(guò)仔細(xì)挑選的,以確保各個(gè)分支都可以測(cè)試到:
void test_redblacktree_delete(RBTree* tree, int key)


{
RBNode* node = RBTree_search(*tree, key);
assert(node != RBTree_nil());

printf("\n刪除節(jié)點(diǎn) %d \n", node->key);
node = RBTree_delete(tree, node);
free(node);
RBTree_print(*tree);
}

void test_redblacktree()


{
const int length = 14;

int array[length] =
{
2, 3, 4, 6, 7, 11, 9, 18, 12, 14, 19, 17, 22, 20
};

int i;
RBTree tree = RBTree_nil();
RBNode* node = NULL;

// 插入節(jié)點(diǎn)生成樹(shù)

for (i = 0; i < length; i++)
{
node = (RBNode*)malloc(sizeof(RBNode));
node->key = array[i];
node->color = RB_Red;
node->parent = RBTree_nil();
node->leftChild = RBTree_nil();
node->rightChild = RBTree_nil();

RBTree_insert(&tree, node);
}

RBTree_print(tree);

// 插入測(cè)試
node = (RBNode*)malloc(sizeof(RBNode));
node->key = 21;

printf("\n插入節(jié)點(diǎn) %d\n", node->key);

RBTree_insert(&tree, node);
RBTree_print(tree);

// 查找測(cè)試
i = 6;
node = RBTree_search(tree, i);


if (node != RBTree_nil())
{
printf("\n在紅黑樹(shù)中找到節(jié)點(diǎn) %d\n", node->key);
}

else
{
printf("\n在紅黑樹(shù)中找不到節(jié)點(diǎn) %d\n", i);
}

// 刪除測(cè)試
//
i = 4;// 取值 1, 2, 3, 4,分別對(duì)應(yīng) case 1, 2, 3, 4

switch (i)

{
case 1: // 兄弟為紅色
test_redblacktree_delete(&tree, 3);
break;

case 2: // 兄弟為黑色,且兄弟的兩孩子均為黑色
test_redblacktree_delete(&tree, 12);
break;

case 3: // 兄弟為黑色,且兄弟的左孩子為紅色,右孩子均為黑色
test_redblacktree_delete(&tree, 19);
break;

case 4: // 兄弟為黑色,且兄弟的右孩子為紅色
test_redblacktree_delete(&tree, 9);
break;
}

test_redblacktree_delete(&tree, 21);

// 刪除樹(shù)

for (i = 0; i < length; i++)
{
node = RBTree_search(tree, array[i]);


if (node != RBTree_nil())
{
printf("刪除 %d\n", node->key);
node = RBTree_delete(&tree, node);
free(node);
}
}

assert(tree == RBTree_nil());
}

測(cè)試結(jié)果
===============================================
創(chuàng)建紅黑樹(shù)
-------------------------------
第 1 層, 6(B)
第 2 層, 3(B)
第 3 層, 2(B)
第 3 層, 4(B)
第 2 層, 12(B)
第 3 層, 9(R)
第 4 層, 7(B)
第 4 層, 11(B)
第 3 層, 18(R)
第 4 層, 14(B)
第 5 層, 17(R)
第 4 層, 20(B)
第 5 層, 19(R)
第 5 層, 22(R)
插入節(jié)點(diǎn) 21
-------------------------------
第 1 層, 6(B)
第 2 層, 3(B)
第 3 層, 2(B)
第 3 層, 4(B)
第 2 層, 12(R)
第 3 層, 9(B)
第 4 層, 7(B)
第 4 層, 11(B)
第 3 層, 18(B)
第 4 層, 14(B)
第 5 層, 17(R)
第 4 層, 20(R)
第 5 層, 19(B)
第 5 層, 22(B)
第 6 層, 21(R)
在紅黑樹(shù)中找到節(jié)點(diǎn) 6
-------------------------------
刪除節(jié)點(diǎn) 9
-------------------------------
第 1 層, 6(B)
第 2 層, 3(B)
第 3 層, 2(B)
第 3 層, 4(B)
第 2 層, 18(R)
第 3 層, 12(B)
第 4 層, 11(B)
第 5 層, 7(R)
第 4 層, 14(B)
第 5 層, 17(R)
第 3 層, 20(B)
第 4 層, 19(B)
第 4 層, 22(B)
第 5 層, 21(R)
刪除節(jié)點(diǎn) 21
-------------------------------
第 1 層, 6(B)
第 2 層, 3(B)
第 3 層, 2(B)
第 3 層, 4(B)
第 2 層, 18(R)
第 3 層, 12(B)
第 4 層, 11(B)
第 5 層, 7(R)
第 4 層, 14(B)
第 5 層, 17(R)
第 3 層, 20(B)
第 4 層, 19(B)
第 4 層, 22(B)
刪除 2
刪除 3
刪除 4
刪除 6
刪除 7
刪除 11
刪除 18
刪除 12
刪除 14
刪除 19
刪除 17
刪除 22
刪除 20
測(cè)試結(jié)束