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

// 沒有左孩子,返回自身

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

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

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

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

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

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


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

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

// 沒有右孩子,向上找到的第一個左分支節(jié)點為其直接后繼,
// 即 node 為其直接后繼的左孩子樹中的最大元素。
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ù)紅黑樹性質(zhì),以及 node 的父親的顏色為紅色,
// 可以肯定 node 的祖父節(jié)點一定存在
grand = parent->parent;

// 確定叔父節(jié)點

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

// case 1: 叔父節(jié)點為紅色
// 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é)點為黑色
// 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
{
// 與上面的情況對稱
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é)點 node 插入樹 tree 內(nèi),然后將 node 著色為紅色,此時,樹可能不再
// 滿足紅黑樹性質(zhì),因此調(diào)用 RBTree_insert_fixup 來對節(jié)點重新著色調(diào)整。
void RBTree_insert(RBTree* tree, RBNode* node)


{
assert(tree && node);

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

// 像二叉樹一樣,在樹中查找適當(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;

// 樹為空

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

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

else
{
parent->rightChild = node;
}

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

// 調(diào)整樹使之滿足紅黑樹性質(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é)點

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

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

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é)點的兩孩子均為黑色
if (brother->leftChild->color == RB_Black

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


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

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é)點的右孩子為紅色
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é)點為紅色

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é)點的兩孩子均為黑色
if (brother->leftChild->color == RB_Black

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


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

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é)點的右孩子為紅色
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;
}
測試代碼,測試數(shù)組中的數(shù)字與測試步驟是經(jīng)過仔細(xì)挑選的,以確保各個分支都可以測試到:
void test_redblacktree_delete(RBTree* tree, int key)


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

printf("\n刪除節(jié)點 %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é)點生成樹

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);

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

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

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

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


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

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

// 刪除測試
//
i = 4;// 取值 1, 2, 3, 4,分別對應(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);

// 刪除樹

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());
}

測試結(jié)果
===============================================
創(chuàng)建紅黑樹
-------------------------------
第 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é)點 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)
在紅黑樹中找到節(jié)點 6
-------------------------------
刪除節(jié)點 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é)點 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
測試結(jié)束