rbtree.c
/**
* C語言實現(xiàn)的紅黑樹(Red Black Tree)
*
* @author skywang
* @date 2013/11/18
*/
#include
#include
#include "rbtree.h"
#define rb_parent(r) ((r)->parent)
#define rb_color(r) ((r)->color)
#define rb_is_red(r) ((r)->color==RED)
#define rb_is_black(r) ((r)->color==BLACK)
#define rb_set_black(r) do { (r)->color = BLACK; } while (0)
#define rb_set_red(r) do { (r)->color = RED; } while (0)
#define rb_set_parent(r,p) do { (r)->parent = (p); } while (0)
#define rb_set_color(r,c) do { (r)->color = (c); } while (0)
/*
* 創(chuàng)建紅黑樹,返回"紅黑樹的根"!
*/
RBRoot* create_rbtree()
{
RBRoot *root = (RBRoot *)malloc(sizeof(RBRoot));
root->node = NULL;
return root;
}
/*
* 前序遍歷"紅黑樹"
*/
static void preorder(RBTree tree)
{
if(tree != NULL)
{
printf("%d ", tree->key);
preorder(tree->left);
preorder(tree->right);
}
}
void preorder_rbtree(RBRoot *root)
{
if (root)
preorder(root->node);
}
/*
* 中序遍歷"紅黑樹"
*/
static void inorder(RBTree tree)
{
if(tree != NULL)
{
inorder(tree->left);
printf("%d ", tree->key);
inorder(tree->right);
}
}
void inorder_rbtree(RBRoot *root)
{
if (root)
inorder(root->node);
}
/*
* 后序遍歷"紅黑樹"
*/
static void postorder(RBTree tree)
{
if(tree != NULL)
{
postorder(tree->left);
postorder(tree->right);
printf("%d ", tree->key);
}
}
void postorder_rbtree(RBRoot *root)
{
if (root)
postorder(root->node);
}
/*
* (遞歸實現(xiàn))查找"紅黑樹x"中鍵值為key的節(jié)點
*/
static Node* search(RBTree x, Type key)
{
if (x==NULL || x->key==key)
return x;
if (key < x->key)
return search(x->left, key);
else
return search(x->right, key);
}
int rbtree_search(RBRoot *root, Type key)
{
if (root)
return search(root->node, key)? 0 : -1;
}
/*
* (非遞歸實現(xiàn))查找"紅黑樹x"中鍵值為key的節(jié)點
*/
static Node* iterative_search(RBTree x, Type key)
{
while ((x!=NULL) && (x->key!=key))
{
if (key < x->key)
x = x->left;
else
x = x->right;
}
return x;
}
int iterative_rbtree_search(RBRoot *root, Type key)
{
if (root)
return iterative_search(root->node, key) ? 0 : -1;
}
/*
* 查找最小結點:返回tree為根結點的紅黑樹的最小結點。
*/
static Node* minimum(RBTree tree)
{
if (tree == NULL)
return NULL;
while(tree->left != NULL)
tree = tree->left;
return tree;
}
int rbtree_minimum(RBRoot *root, int *val)
{
Node *node;
if (root)
node = minimum(root->node);
if (node == NULL)
return -1;
*val = node->key;
return 0;
}
/*
* 查找最大結點:返回tree為根結點的紅黑樹的最大結點。
*/
static Node* maximum(RBTree tree)
{
if (tree == NULL)
return NULL;
while(tree->right != NULL)
tree = tree->right;
return tree;
}
int rbtree_maximum(RBRoot *root, int *val)
{
Node *node;
if (root)
node = maximum(root->node);
if (node == NULL)
return -1;
*val = node->key;
return 0;
}
/*
* 找結點(x)的后繼結點。即,查找"紅黑樹中數(shù)據(jù)值大于該結點"的"最小結點"。
*/
static Node* rbtree_successor(RBTree x)
{
// 如果x存在右孩子,則"x的后繼結點"為 "以其右孩子為根的子樹的最小結點"。
if (x->right != NULL)
return minimum(x->right);
// 如果x沒有右孩子。則x有以下兩種可能:
// (01) x是"一個左孩子",則"x的后繼結點"為 "它的父結點"。
// (02) x是"一個右孩子",則查找"x的最低的父結點,并且該父結點要具有左孩子",找到的這個"最低的父結點"就是"x的后繼結點"。
Node* y = x->parent;
while ((y!=NULL) && (x==y->right))
{
x = y;
y = y->parent;
}
return y;
}
/*
* 找結點(x)的前驅結點。即,查找"紅黑樹中數(shù)據(jù)值小于該結點"的"最大結點"。
*/
static Node* rbtree_predecessor(RBTree x)
{
// 如果x存在左孩子,則"x的前驅結點"為 "以其左孩子為根的子樹的最大結點"。
if (x->left != NULL)
return maximum(x->left);
// 如果x沒有左孩子。則x有以下兩種可能:
// (01) x是"一個右孩子",則"x的前驅結點"為 "它的父結點"。
// (01) x是"一個左孩子",則查找"x的最低的父結點,并且該父結點要具有右孩子",找到的這個"最低的父結點"就是"x的前驅結點"。
Node* y = x->parent;
while ((y!=NULL) && (x==y->left))
{
x = y;
y = y->parent;
}
return y;
}
/*
* 對紅黑樹的節(jié)點(x)進行左旋轉
*
* 左旋示意圖(對節(jié)點x進行左旋):
* px px
* / /
* x y
* / \\ --(左旋)--> / \\ #
* lx y x ry
* / \\ / \\
* ly ry lx ly
*
*
*/
static void rbtree_left_rotate(RBRoot *root, Node *x)
{
// 設置x的右孩子為y
Node *y = x->right;
// 將 “y的左孩子” 設為 “x的右孩子”;
// 如果y的左孩子非空,將 “x” 設為 “y的左孩子的父親”
x->right = y->left;
if (y->left != NULL)
y->left->parent = x;
// 將 “x的父親” 設為 “y的父親”
y->parent = x->parent;
if (x->parent == NULL)
{
//tree = y; // 如果 “x的父親” 是空節(jié)點,則將y設為根節(jié)點
root->node = y; // 如果 “x的父親” 是空節(jié)點,則將y設為根節(jié)點
}
else
{
if (x->parent->left == x)
x->parent->left = y; // 如果 x是它父節(jié)點的左孩子,則將y設為“x的父節(jié)點的左孩子”
else
x->parent->right = y; // 如果 x是它父節(jié)點的左孩子,則將y設為“x的父節(jié)點的左孩子”
}
// 將 “x” 設為 “y的左孩子”
y->left = x;
// 將 “x的父節(jié)點” 設為 “y”
x->parent = y;
}
/*
* 對紅黑樹的節(jié)點(y)進行右旋轉
*
* 右旋示意圖(對節(jié)點y進行左旋):
* py py
* / /
* y x
* / \\ --(右旋)--> / \\ #
* x ry lx y
* / \\ / \\ #
* lx rx rx ry
*
*/
static void rbtree_right_rotate(RBRoot *root, Node *y)
{
// 設置x是當前節(jié)點的左孩子。
Node *x = y->left;
// 將 “x的右孩子” 設為 “y的左孩子”;
// 如果"x的右孩子"不為空的話,將 “y” 設為 “x的右孩子的父親”
y->left = x->right;
if (x->right != NULL)
x->right->parent = y;
// 將 “y的父親” 設為 “x的父親”
x->parent = y->parent;
if (y->parent == NULL)
{
//tree = x; // 如果 “y的父親” 是空節(jié)點,則將x設為根節(jié)點
root->node = x; // 如果 “y的父親” 是空節(jié)點,則將x設為根節(jié)點
}
else
{
if (y == y->parent->right)
y->parent->right = x; // 如果 y是它父節(jié)點的右孩子,則將x設為“y的父節(jié)點的右孩子”
else
y->parent->left = x; // (y是它父節(jié)點的左孩子) 將x設為“x的父節(jié)點的左孩子”
}
// 將 “y” 設為 “x的右孩子”
x->right = y;
// 將 “y的父節(jié)點” 設為 “x”
y->parent = x;
}
/*
* 紅黑樹插入修正函數(shù)
*
* 在向紅黑樹中插入節(jié)點之后(失去平衡),再調用該函數(shù);
* 目的是將它重新塑造成一顆紅黑樹。
*
* 參數(shù)說明:
* root 紅黑樹的根
* node 插入的結點 // 對應《算法導論》中的z
*/
static void rbtree_insert_fixup(RBRoot *root, Node *node)
{
Node *parent, *gparent;
// 若“父節(jié)點存在,并且父節(jié)點的顏色是紅色”
while ((parent = rb_parent(node)) && rb_is_red(parent))
{
gparent = rb_parent(parent);
//若“父節(jié)點”是“祖父節(jié)點的左孩子”
if (parent == gparent->left)
{
// Case 1條件:叔叔節(jié)點是紅色
{
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條件:叔叔是黑色,且當前節(jié)點是右孩子
if (parent->right == node)
{
Node *tmp;
rbtree_left_rotate(root, parent);
tmp = parent;
parent = node;
node = tmp;
}
// Case 3條件:叔叔是黑色,且當前節(jié)點是左孩子。
rb_set_black(parent);
rb_set_red(gparent);
rbtree_right_rotate(root, gparent);
}
else//若“z的父節(jié)點”是“z的祖父節(jié)點的右孩子”
{
// Case 1條件:叔叔節(jié)點是紅色
{
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條件:叔叔是黑色,且當前節(jié)點是左孩子
if (parent->left == node)
{
Node *tmp;
rbtree_right_rotate(root, parent);
tmp = parent;
parent = node;
node = tmp;
}
// Case 3條件:叔叔是黑色,且當前節(jié)點是右孩子。
rb_set_black(parent);
rb_set_red(gparent);
rbtree_left_rotate(root, gparent);
}
}
// 將根節(jié)點設為黑色
rb_set_black(root->node);
}
/*
* 添加節(jié)點:將節(jié)點(node)插入到紅黑樹中
*
* 參數(shù)說明:
* root 紅黑樹的根
* node 插入的結點 // 對應《算法導論》中的z
*/
static void rbtree_insert(RBRoot *root, Node *node)
{
Node *y = NULL;
Node *x = root->node;
// 1. 將紅黑樹當作一顆二叉查找樹,將節(jié)點添加到二叉查找樹中。
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設為“y的左孩子”
else
y->right = node; // 情況3:(“node所包含的值” >= “y所包含的值”)將node設為“y的右孩子”
}
else
{
root->node = node; // 情況1:若y是空節(jié)點,則將node設為根
}
// 2. 設置節(jié)點的顏色為紅色
node->color = RED;
// 3. 將它重新修正為一顆二叉查找樹
rbtree_insert_fixup(root, node);
}
/*
* 創(chuàng)建結點
*
* 參數(shù)說明:
* key 是鍵值。
* parent 是父結點。
* left 是左孩子。
* right 是右孩子。
*/
static Node* create_rbtree_node(Type key, Node *parent, Node *left, Node* right)
{
Node* p;
if ((p = (Node *)malloc(sizeof(Node))) == NULL)
return NULL;
p->key = key;
p->left = left;
p->right = right;
p->parent = parent;
p->color = BLACK; // 默認為黑色
return p;
}
/*
* 新建結點(節(jié)點鍵值為key),并將其插入到紅黑樹中
*
* 參數(shù)說明:
* root 紅黑樹的根
* key 插入結點的鍵值
* 返回值:
* 0,插入成功
* -1,插入失敗
*/
int insert_rbtree(RBRoot *root, Type key)
{
Node *node; // 新建結點
// 不允許插入相同鍵值的節(jié)點。
// (若想允許插入相同鍵值的節(jié)點,注釋掉下面兩句話即可!)
if (search(root->node, key) != NULL)
return -1;
// 如果新建結點失敗,則返回。
if ((node=create_rbtree_node(key, NULL, NULL, NULL)) == NULL)
return -1;
rbtree_insert(root, node);
return 0;
}
/*
* 紅黑樹刪除修正函數(shù)
*
* 在從紅黑樹中刪除插入節(jié)點之后(紅黑樹失去平衡),再調用該函數(shù);
* 目的是將它重新塑造成一顆紅黑樹。
*
* 參數(shù)說明:
* root 紅黑樹的根
* node 待修正的節(jié)點
*/
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的倆個孩子也都是黑色的
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的倆個孩子也都是黑色的
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);
}
/*
* 刪除結點
*
* 參數(shù)說明:
* tree 紅黑樹的根結點
* node 刪除的結點
*/
void rbtree_delete(RBRoot *root, Node *node)
{
Node *child, *parent;
int color;
// 被刪除節(jié)點的"左右孩子都不為空"的情況。
if ( (node->left!=NULL) && (node->right!=NULL) )
{
// 被刪節(jié)點的后繼節(jié)點。(稱為"取代節(jié)點")
// 用它來取代"被刪節(jié)點"的位置,然后再將"被刪節(jié)點"去掉。
Node *replace = node;
// 獲取后繼節(jié)點
replace = replace->right;
while (replace->left != NULL)
replace = replace->left;
// "node節(jié)點"不是根節(jié)點(只有根節(jié)點不存在父節(jié)點)
if (rb_parent(node))
{
if (rb_parent(node)->left == node)
rb_parent(node)->left = replace;
else
rb_parent(node)->right = replace;
}
else
// "node節(jié)點"是根節(jié)點,更新根節(jié)點。
root->node = replace;
// child是"取代節(jié)點"的右孩子,也是需要"調整的節(jié)點"。
// "取代節(jié)點"肯定不存在左孩子!因為它是一個后繼節(jié)點。
child = replace->right;
parent = rb_parent(replace);
// 保存"取代節(jié)點"的顏色
color = rb_color(replace);
// "被刪除節(jié)點"是"它的后繼節(jié)點的父節(jié)點"
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é)點"的顏色
color = node->color;
if (child)
child->parent = parent;
// "node節(jié)點"不是根節(jié)點
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);
}
/*
* 刪除鍵值為key的結點
*
* 參數(shù)說明:
* tree 紅黑樹的根結點
* key 鍵值
*/
void delete_rbtree(RBRoot *root, Type key)
{
Node *z, *node;
if ((z = search(root->node, key)) != NULL)
rbtree_delete(root, z);
}
/*
* 銷毀紅黑樹
*/
static void rbtree_destroy(RBTree tree)
{
if (tree==NULL)
return ;
if (tree->left != NULL)
rbtree_destroy(tree->left);
if (tree->right != NULL)
rbtree_destroy(tree->right);
free(tree);
}
void destroy_rbtree(RBRoot *root)
{
if (root != NULL)
rbtree_destroy(root->node);
free(root);
}
/*
* 打印"紅黑樹"
*
* tree -- 紅黑樹的節(jié)點
* key -- 節(jié)點的鍵值
* direction -- 0,表示該節(jié)點是根節(jié)點;
* -1,表示該節(jié)點是它的父結點的左孩子;
* 1,表示該節(jié)點是它的父結點的右孩子。
*/
static void rbtree_print(RBTree tree, Type key, int direction)
{
if(tree != NULL)
{
if(direction==0) // tree是根節(jié)點
printf("%2d(B) is root\\n", tree->key);
else // tree是分支節(jié)點
printf("%2d(%s) is %2d's %6s child\\n", tree->key, rb_is_red(tree)?"R":"B", key, direction==1?"right" : "left");
rbtree_print(tree->left, tree->key, -1);
rbtree_print(tree->right,tree->key, 1);
}
}
void print_rbtree(RBRoot *root)
{
if (root!=NULL && root->node!=NULL)
rbtree_print(root->node, root->node->key, 0);
}
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。
舉報投訴
-
數(shù)據(jù)
+關注
關注
8文章
7002瀏覽量
88943 -
代碼
+關注
關注
30文章
4779瀏覽量
68525 -
查找算法
+關注
關注
0文章
6瀏覽量
5527
發(fā)布評論請先 登錄
相關推薦
STM32 library、應用、源代碼等資料 歸檔貼(查找方便)
/jishu_423003_1_1.htmlSTM32F1,STM32F2,STM32F4 外設固件封裝庫 含源碼和libhttps://bbs.elecfans.com/jishu_419945_1_1.html芯達stm32源代碼
發(fā)表于 04-01 11:05
簡單的查找算法
幾個比較基礎的查找算法:1. 無序鏈表的查找:主要是使用鏈表的遍歷操作來實現(xiàn)對于每個元素的訪問,和對比。通過在for循環(huán)中的if來判斷key相等的元素。如果找到就彈出val。如果沒有就返回null
發(fā)表于 12-27 22:33
isis 7 professional_元件查找代碼
isis 7 professional元件查找代碼有各總isis 7 professional元件的查找代碼
發(fā)表于 12-08 15:58
?7次下載
自動機終結字查找算法實現(xiàn)優(yōu)化綜述
|4)的自動機終結字查找算法,該算法是至今僅有的專門用于計算自動機的終結字的算法。以現(xiàn)有同步自動機的同步字
發(fā)表于 04-28 15:49
?3次下載
常見的查找算法匯總(含詳細代碼)2
今天就把常見****查找算法也總結個通透, 還有詳細的代碼解釋, 真的是寫完這篇感覺腦子已經(jīng)不是自己的了,還希望大家好好利用。
常見的查找算法匯總(含詳細代碼)3
今天就把常見****查找算法也總結個通透, 還有詳細的代碼解釋, 真的是寫完這篇感覺腦子已經(jīng)不是自己的了,還希望大家好好利用。
常見的查找算法匯總(含詳細代碼)5
今天就把常見****查找算法也總結個通透, 還有詳細的代碼解釋, 真的是寫完這篇感覺腦子已經(jīng)不是自己的了,還希望大家好好利用。
評論