說起紅黑樹,最頭疼的就是插入或刪除後引起的不平衡,各種旋轉,着色細節讓人難以理解。我一開始是網上找別人的代碼來看,看的一頭霧水,還是算法導論上的的僞代碼到位,不用糾結於各種細節,雖然我現在依然沒有徹底搞清楚,但是根據書上的僞代碼寫了一遍,居然也能通過驗證。
這裏不做深入分析,只要對紅黑樹有個大概的瞭解,相信書上的算法就好。對插入和刪除要做哪些事情大體瞭解下,不用探究細節。不廢話,直接上代碼,我的一些理解寫在了代碼註釋中
更新一下,刪除節點在remove_rbt_node方法末尾,在執行待刪除節點與他右子樹最左邊的節點交換後,調用free,這點算法導論書上沒有寫出
調試中輸出了涉及旋轉、交換的節點的值,直觀的感受插入和刪除操作的過程
頭文件
/*
* File: rb_tree.h
* Author: weng
*
* Created on 2018年11月8日, 下午9:40
*/
#ifndef RB_TREE_H
#define RB_TREE_H
#ifdef __cplusplus
extern "C" {
#endif
#define DEBUG_RBT 1
typedef int RBTKey;
enum rbt_color {
RED = 0, BLACK
};
struct rbt_node {
struct rbt_node* parent;
struct rbt_node* left;
struct rbt_node* right;
RBTKey key;
enum rbt_color color;
};
struct rb_tree {
struct rbt_node* root;
struct rbt_node* nil;
};
typedef struct rbt_node RBTNode;
typedef struct rb_tree RBTree;
/*
* 常用方法
*/
RBTree* create_rbtree(void); //使用malloc在堆中創建紅黑樹並初始化
RBTree* init_rbtree(RBTree* t); //初始化
RBTree* insert_rbt_node(RBTree* t, const RBTKey key); //插入key
RBTree* remove_rbt_node(RBTree* t, const RBTKey key); //刪除key對應節點
void clear_rbtree(RBTree* t); //後序遍歷,free樹中的節點,對於t需要另行處理
void display_rbt(RBTree* t); //中序遍歷
void display_rbt_prevorder(RBTree* t); //先序遍歷
void display_rbt_postorder(RBTree* t); //後序遍歷
void show_rbt(RBTree* t); //圖示
/*
* 輔助函數
* 參數中RBTree* t, RBTNode* r
* t->root爲根節點, r爲待操作的節點
*/
RBTNode* create_rbt_node(const RBTKey key); //使用malloc在堆中創建節點並初始化
RBTree* rbt_insert_fixup(RBTree* t, RBTNode* r); //插入後平衡
RBTree* rbt_left_rotate(RBTree* t, RBTNode* r); //左旋
RBTree* rbt_right_rotate(RBTree* t, RBTNode* r); //右旋
RBTree* rbt_transplant(RBTree* t, RBTNode* u, RBTNode* v); //互換節點
RBTree* rbt_delete_fixup(RBTree* t, RBTNode* r); //刪除後平衡
RBTNode* rbt_minimum(RBTree* t, RBTNode* r); //返回將與待刪除節點互換的節點 \
//這裏是用待刪除節點的右孩子的最左邊一個節點與待刪除節點互換,使得他們位置變換, \
//然後執行刪除,這樣樹的整體結構不變,之後執行平衡策略
void clear_rbt_node_post(RBTree* t, RBTNode* r);
void display_rbt_node(RBTree* t, RBTNode* r);
void display_rbt_node_prev(RBTree* t, RBTNode* r);
void display_rbt_node_post(RBTree* t, RBTNode* r);
void show_rbt_node(RBTree* t, RBTNode* r, int high, int n); //
#ifdef __cplusplus
}
#endif
#endif /* RB_TREE_H */
方法實現源文件
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
#include "rb_tree.h"
#include <stdio.h>
#include <stdlib.h>
RBTree* create_rbtree(void) {
RBTree* t = (RBTree*) malloc(sizeof (RBTree));
/*
t->nil = create_rbt_node(0);
t->nil->color = BLACK;
t->root = t->nil;
return t;
*/
init_rbtree(t);
return t;
}
RBTree* init_rbtree(RBTree* t) {
t->nil = create_rbt_node(0);
t->nil->color = BLACK;
t->root = t->nil;
return t;
}
RBTree* insert_rbt_node(RBTree* t, const RBTKey key) {
RBTNode* rp = t->root; //插入路徑上的迭代器//書上記作x
RBTNode* parent = t->nil; //迭代器的父節點//y
/*
RBTNode* r = create_rbt_node(key); //待插入的節點//z
*/
while (rp != t->nil) {
parent = rp;
if (key < rp->key)
rp = rp->left;
else if (key > rp->key)
rp = rp->right;
else
return t; //樹中已有key,返回
}
RBTNode* r = create_rbt_node(key); //待插入的節點//z
r->parent = parent;
r->left = t->nil;
r->right = t->nil;
if (parent == t->nil)
t->root = r;
else if (key < parent->key)
parent->left = r;
else
parent->right = r;
t = rbt_insert_fixup(t, r);
return t;
}
RBTree* remove_rbt_node(RBTree* t, const RBTKey key) {
RBTNode* rp = t->root; //刪除路徑上的迭代器//y
while (rp != t->nil) {
if (key < rp->key)
rp = rp->left;
else if (key > rp->key)
rp = rp->right;
else
break; //找到key
}
if (rp == t->nil)
return t; //未找到
RBTNode* z = rp; //z 待刪除key的節點
enum rbt_color y_o_c = rp->color; //記錄顏色
RBTNode* x; //記錄z的孩子節點
if (z->left == t->nil) {
x = z->right;
rbt_transplant(t, z, z->right);
} else if (z->right == t->nil) {
x = z->left;
rbt_transplant(t, z, z->left);
} else {
rp = rbt_minimum(t, z->right);
/*
//以下4行爲tree_minimum方法
rp = z->right;
while (rp->left != t->nil) {
rp = rp->left;
}
*/
y_o_c = rp->color;
x = rp->right;
if (rp->parent == z)
x->parent = rp;
else {
rbt_transplant(t, rp, rp->right);
rp->right = z->right;
rp->right->parent = rp;
}
rbt_transplant(t, z, rp);
rp->left = z->left;
rp->left->parent = rp;
rp->color = z->color;
}
#ifdef DEBUG_RBT
printf("刪除節點 %d\n", u->key);
#endif
free(z);//刪除節點
if (y_o_c == BLACK)
rbt_delete_fixup(t, x);
}
void clear_rbtree(RBTree* t) {
if (t == NULL)return;
clear_rbt_node_post(t, t->root);
if (t->nil != NULL)
free(t->nil);
}
void display_rbt(RBTree* t) {
if (t == NULL)return;
display_rbt_node(t, t->root);
printf("\n");
}
void display_rbt_prevorder(RBTree* t) {
if (t == NULL)return;
display_rbt_node_prev(t, t->root);
printf("\n");
}
void display_rbt_postorder(RBTree* t) {
if (t == NULL)return;
display_rbt_node_post(t, t->root);
printf("\n");
}
void show_rbt(RBTree* t) {
if (t == NULL)return;
int h = 0;
int n = 0;
show_rbt_node(t, t->root, h, n);
}
RBTNode* create_rbt_node(const RBTKey key) {
RBTNode* r = (RBTNode*) malloc(sizeof (RBTNode));
r->left = r->right = r->parent = NULL;
r->color = RED;
r->key = key;
return r;
}
/*
* 參數中RBTree* t, RBTNode* r
* t->root爲根節點, r爲待操作的節點
*/
RBTree* rbt_insert_fixup(RBTree* t, RBTNode* r) {
while (r->parent->color == RED) {
if (r->parent == r->parent->parent->left) {
RBTNode* u = r->parent->parent->right; //r的叔叔uncle;//y
if (u->color == RED) {//case 1
r->parent->color = BLACK;
u->color = BLACK;
r->parent->parent->color = RED;
r = r->parent->parent;
} else if (r == r->parent->right) {//case 2
r = r->parent;
rbt_left_rotate(t, r);
} else {//case 3//第三版書上這裏沒有else,加上
r->parent->color = BLACK;
r->parent->parent->color = RED;
rbt_right_rotate(t, r->parent->parent);
}
} else {
RBTNode* u = r->parent->parent->left; //r的叔叔uncle;//y
if (u->color == RED) {
r->parent->color = BLACK;
u->color = BLACK;
r->parent->parent->color = RED;
r = r->parent->parent;
} else if (r == r->parent->left) {
r = r->parent;
rbt_right_rotate(t, r);
} else {//
r->parent->color = BLACK;
r->parent->parent->color = RED;
rbt_left_rotate(t, r->parent->parent);
}
}
}//while
t->root->color = BLACK;
return t;
}
RBTree* rbt_left_rotate(RBTree* t, RBTNode* r) {
if (r->right != t->nil) {
RBTNode* child = r->right; //y
#ifdef DEBUG_RBT
printf("left_rolate %d<->%d\n", r->key, child->key);
#endif
r->right = child->left;
if (child->left != t->nil)
child->left->parent = r;
child->parent = r->parent;
if (r->parent == t->nil)
t->root = child;
else if (r == r->parent->left)
r->parent->left = child;
else
r->parent->right = child;
child->left = r;
r->parent = child;
}
return t;
}
RBTree* rbt_right_rotate(RBTree* t, RBTNode* r) {
if (r->left != t->nil) {//書上僞代碼之前假設這個條件,
//根節點的父節點爲nil已經在init_rbtree()方法中初始化
RBTNode* child = r->left; //y
#ifdef DEBUG_RBT
printf("right_rolate %d<->%d\n", r->key, child->key);
#endif
r->left = child->right;
if (child->right != t->nil)
child->right->parent = r;
child->parent = r->parent;
if (r->parent == t->nil)
t->root = child;
else if (r == r->parent->right)
r->parent->right = child;
else
r->parent->left = child;
child->right = r;
r->parent = child;
}
return t;
}
RBTree* rbt_transplant(RBTree* t, RBTNode* u, RBTNode* v) {
if (u->parent == t->nil)
t->root = v;
else if (u == u->parent->left)
u->parent->left = v;
else
u->parent->right = v;
v->parent = u->parent;
#ifdef DEBUG_RBT
printf("transplant %d %d\n", u->key, v->key);
#endif
return t;
}
RBTree* rbt_delete_fixup(RBTree* t, RBTNode* x) {//r=x
while (x != t->root && x->color == BLACK) {
RBTNode* w; //記錄x的兄弟節點
if (x == x->parent->left) {
w = x->parent->right;
if (w->color == RED) {//case 1
w->color = BLACK;
x->parent->color = RED;
rbt_left_rotate(t, x->parent);
w = x->parent->right;
}
if (w->left->color == BLACK && w->right->color == BLACK) {//case 2
w->color = RED;
x = x->parent;
} else if (w->right->color == BLACK) {//case 3
w->left->color = BLACK;
w->color = RED;
rbt_right_rotate(t, w);
w = x->parent->right;
} else {//else一定要加上//case 4
w->color = x->parent->color; //case 4
x->parent->color = BLACK;
w->right->color = BLACK;
rbt_left_rotate(t, x->parent);
x = t->root;
}
} else {//鏡像
w = x->parent->left;
if (w->color == RED) {//case 1
w->color = BLACK;
x->parent->color = RED;
rbt_right_rotate(t, x->parent);
w = x->parent->left;
}
if (w->right->color == BLACK && w->left->color == BLACK) {//case 2
w->color = RED;
x = x->parent;
} else if (w->left->color == BLACK) {//case 3
w->right->color = BLACK;
w->color = RED;
rbt_left_rotate(t, w);
w = x->parent->left;
} else {
w->color = x->parent->color; //case 4
x->parent->color = BLACK;
w->left->color = BLACK;
rbt_right_rotate(t, x->parent);
x = t->root;
}
}
}//while
x->color = BLACK;
}
RBTNode* rbt_minimum(RBTree* t, RBTNode* r) {
while (r->left != t->nil) {
r = r->left;
}
return r;
}
void clear_rbt_node_post(RBTree* t, RBTNode* r) {
if (r != t->nil) {
clear_rbt_node_post(t, r->left);
clear_rbt_node_post(t, r->right);
if (r != NULL)
free(r);
}
}
void display_rbt_node(RBTree* t, RBTNode* r) {
if (r != t->nil) {
display_rbt_node(t, r->left);
/*
printf("%d\n", r->key);
*/
printf("%d ", r->key);
display_rbt_node(t, r->right);
}
}
void display_rbt_node_prev(RBTree* t, RBTNode* r) {
if (r != t->nil) {
/*
printf("%d\n", r->key);
*/
printf("%d ", r->key);
display_rbt_node_prev(t, r->left);
display_rbt_node_prev(t, r->right);
}
}
void display_rbt_node_post(RBTree* t, RBTNode* r) {
if (r != t->nil) {
display_rbt_node_post(t, r->left);
display_rbt_node_post(t, r->right);
/*
printf("%d\n", r->key);
*/
printf("%d ", r->key);
}
}
void show_rbt_node(RBTree* t, RBTNode* r, int high, int n) {
if (r != t->nil) {
show_rbt_node(t, r->right, high + 7, n + 1);
int i = 0;
while (i != high) {
if (i % 7 == 0) {
if (i >= 7 * n)
printf("|");
else
printf(" ");
} else
printf(" ");
i++;
}
if (r->color == RED)
printf("|-<R>");
else printf("|-<B>");
printf("%2d-\n", r->key);
show_rbt_node(t, r->left, high + 7, n + 1);
} else {
int i = 0;
while (i != high) {
if (i % 7 == 0) {
if (i >= 7 * n)
printf("|");
else
printf(" ");
} else
printf(" ");
i++;
}
printf("|-NIL\n");
}
}
測試程序main.c,用隨機數進行插入、刪除測試,多次測試沒有問題
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
/*
* File: main.c
* Author: weng
*
* Created on 2018年11月8日, 下午9:39
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "rb_tree.h"
/*
*
*/
#define N_NODES 50
#define ARRAYSIZE 100001
int main(int argc, char** argv) {
int i, n = 0;
srand(time(0));
int array[ARRAYSIZE];
memset(array, -1, sizeof (array));
RBTree* t = create_rbtree();
for (i = 0; i < N_NODES; i++) {
int num = rand() % N_NODES;
insert_rbt_node(t, num);
/*
num = i;
insert_rbt_node(t, num);
*/
if (num != array[num]) {
printf("插入: %d \n", num);
array[num] = num;
n++;
} else {
printf("重複插入 %d\n", num);
}
}
printf("array: \n");
for (int i = 0; i < ARRAYSIZE; i++)
if (array[i] != -1)
printf("%d ", array[i]);
printf("\nhow many: %d\n", n);
printf("display: \n");
display_rbt(t);
display_rbt_prevorder(t);
display_rbt_postorder(t);
show_rbt(t);
for (i = 0; i < N_NODES; i++) {
int num = rand() % N_NODES;
remove_rbt_node(t, num);
/*
num = i;
remove_rbt_node(t, num);
*/
if (num == array[num]) {
printf("刪除: %d \n", num);
array[num] = -1;
n--;
} else {
printf("重複刪除或不存在 %d\n", num);
}
}
show_rbt(t);
printf("array: \n");
for (int i = 0; i < ARRAYSIZE; i++)
if (array[i] != -1)
printf("%d ", array[i]);
printf("\nhow many: %d\n", n);
printf("display: \n");
display_rbt(t);
display_rbt_prevorder(t);
display_rbt_postorder(t);
clear_rbtree(t);
free(t);
return (EXIT_SUCCESS);
}
這是隨機插入20次並刪除20次的整個過程
其他幾次測試結果圖