红黑树构建,插入,删除以及代码
·
红黑树
完整代码见文末
概念:
- 每个节点都有颜色,红色或者黑色
- 根节点是黑色
- 每个叶子节点是黑色
- 如果一个节点是红色,那么它的两个子节点都是黑色
- 对每个节点来说,从该节点到其子孙节点的所有路径上都有相同的黑色节点。
操作:
- 左旋与右旋
- 插入
- 删除
- 遍历
- 查询
注意:
- 红黑树在插入节点之前就已经是一颗红黑树了,就已经具备以上5个条件了
1.定义
根据上面的概念,可以有下面的定义代码:
#define RED 0
#define BLACK 1
typedef int KEY_TYPE; //可以修改key的类型
typedef struct _rbtree_node{
KEY_TYPE key; //节点的键值
void *value; //节点存储的值,void *类型可以指向任意类型的数据
struct _rbtree_node *right;
struct _rbtree_node *left;
struct _rbtree_node *parent;
unsigned char color;
}rbtree_node;
typedef struct _rbtree{
struct _rbtree_node *root;//根节点
struct _rbtree_node *nil;//哨兵节点
//红黑树中所有的叶子结点都要指向哨兵节点,它不是传统的NULL空指针,它具有节点的属性
}rbtree;
更近 一步可以下面的代码,更具有拓展性和复用性
//定义
#define RED 0
#define BLACK 1
typedef int KEY_TYPE; //可以修改key的类型
//这个宏的作用是将红黑树节点的公共部分(即与具体数据类型无关的部分)抽象出来,便于复用。
//后面需要扩展功能或者将红黑树用于不同的数据类型,只需要修改
//KEY_TYPE和value部分,而不需要重复定义这些公共字段
#define RBTREE_ENTRY(name, type) \
struct name{ \
struct _rbtree_node *right; \
struct _rbtree_node *left; \
struct _rbtree_node *parent; \
unsigned char color; \
}
typedef struct _rbtree_node{
KEY_TYPE key; //节点的键值
void *value; //节点存储的值,void *类型可以指向任意类型的数据
#if 1
struct _rbtree_node *right;
struct _rbtree_node *left;
struct _rbtree_node *parent;
unsigned char color;
#else
RBTREE_ENTRY(, rb_node) node;
#endif
}rbtree_node;
typedef struct _rbtree{
struct _rbtree_node *root;//根节点
struct _rbtree_node *nil;//哨兵节点
//红黑树中所有的叶子结点都要指向哨兵节点,它不是传统的NULL空指针,它具有节点的属性
}rbtree;
2.左旋和右旋
通过旋转可以调整树的高度,达到平衡.

左旋:
- x的右指向y的左
- y左的父指向x
- y的父指向x的父
- x的父指向y
- y的左指向x
- x的父指向y
右旋:
与左旋相称,代码中把左旋的代码,x改为y,y改为x;left与right相互替换
3.插入
插入
- 找到应该插入的位置
- 进行插入
- 对树进行调整,保持红黑树的性质
调整情况罗列:
- 父节点是左子树,叔节点是红色
- 父节点是左子树,叔节点是黑色,当前节点是右孩子
- 父节点是左子树,叔节点是黑色,当前节点是左孩子
- 父节点是右子树,叔节点是红色
- 父节点是右子树,叔节点是黑色,当前节点是右孩子
- 父节点是右子树,叔节点是黑色,当前节点是左孩子
4.删除
删除情况罗列:
- 待删除节点的左右子树都为空
- 直接删除该节点
- 待删除节点左右子树,一个为空,一个不为空
- 直接删除该节点,并让该节点的父节点,指向其左子树or右子树
- 待删除节点的左右子树都不为空
- 找到该待删除的节点的可代替节点,左子树的最大值(肯定没有右孩子,可能都左孩子)or右子树的最小值(肯定没有左孩子,可能有右孩子)
- 删除该可代替节点
- 并用可代替节点,覆盖真正待删除的节点
根据上面三种情况,需要删除的节点都是最多有一个子树
调整情况罗列:
- 当前结点是左孩子,其兄弟节点是红色的
- 当前结点是左孩子,其兄弟节点是黑色的,而且兄弟结点的两个子结点也是黑色的
- 当前结点是左孩子,其兄弟节点是黑色的,而且兄弟结点的左子树是红色,右子树是黑色的
- 当前结点是左孩子,其兄弟节点是黑色的,而且兄弟结点的左子树任意颜色,右子树是红色
- 当前结点是右孩子,其兄弟节点是红色的
- 当前结点是右孩子,其兄弟节点是黑色的,而且兄弟结点的两个子结点也是黑色的
- 当前结点是右孩子,其兄弟节点是黑色的,而且兄弟结点的左子树是黑色,右子树是红色的
- 当前结点是右孩子,其兄弟节点是黑色的,而且兄弟结点的左子树红颜色,右子树任意颜色
5.查找
通过遍历,查找对应的节点
6.遍历
中序遍历,左根右,遍历的结果是有序的
7.测试
对红黑树进行初始化,然后进行插入删除操作
左子树是黑色,右子树是红色的
8. 当前结点是右孩子,其兄弟节点是黑色的,而且兄弟结点的左子树红颜色,右子树任意颜色
5.查找
通过遍历,查找对应的节点
6.遍历
中序遍历,左根右,遍历的结果是有序的
7.测试
对红黑树进行初始化,然后进行插入删除操作
#include <stdio.h>
#include <stdlib.h>
// 1. 定义
#define RED 0
#define BLACK 1
typedef int KEY_TYPE; //可以修改key的类型
// 1.1 宏定义
//这个宏的作用是将红黑树节点的公共部分(即与具体数据类型无关的部分)抽象出来,便于复用。
//后面需要扩展功能或者将红黑树用于不同的数据类型,只需要修改
//KEY_TYPE和value部分,而不需要重复定义这些公共字段
#define RBTREE_ENTRY(name, type) \
struct name{ \
struct _rbtree_node *right; \
struct _rbtree_node *left; \
struct _rbtree_node *parent; \
unsigned char color; \
}
// 1.2 节点定义
typedef struct _rbtree_node{
KEY_TYPE key; //节点的键值
void *value; //节点存储的值,void *类型可以指向任意类型的数据
#if 1
struct _rbtree_node *right;
struct _rbtree_node *left;
struct _rbtree_node *parent;
unsigned char color;
#else
RBTREE_ENTRY(, rb_node) node;
#endif
}rbtree_node;
// 1.3 树定义
typedef struct _rbtree{
struct _rbtree_node *root;//根节点
struct _rbtree_node *nil;//哨兵节点
//红黑树中所有的叶子结点都要指向哨兵节点,它不是传统的NULL空指针,它具有节点的属性
}rbtree;
//函数声明
void rbtree_left_rotate(rbtree* T, rbtree_node* x);//左旋
void rbtree_right_rotate(rbtree* T, rbtree_node* y);//右旋
int key_compare(KEY_TYPE a, KEY_TYPE b);//节点比较
void rbtree_insert(rbtree* T, rbtree_node* z);//插入
void rbtree_insert_fixup(rbtree* T, rbtree_node* z);//插入的调整
rbtree_node* rbtree_min(rbtree* T, rbtree_node* x);//找出节点的子树中最小值
rbtree_node* rbtree_max(rbtree* T, rbtree_node* x);//找出节点的子树中最大值
rbtree_node* rbtree_successor(rbtree* T, rbtree_node* x);//找出替代节点
rbtree_node* rbtree_delete(rbtree* T, rbtree_node* z);//删除节点
void rbtree_delete_fixup(rbtree* T, rbtree_node* x);//删除的调整
rbtree_node* rbtree_search(rbtree* T, KEY_TYPE key);//查找
void rbtree_traversal(rbtree* T, rbtree_node* node);//遍历
// 2.1 左旋
//左旋leftRotate(T,x)---中右->左中
//降低X结点的高度,提高X的右结点(即Y)的高度
void rbtree_left_rotate(rbtree* T, rbtree_node* x) {
rbtree_node* y = x->right;
// 2.1.1
x->right = y->left;
if(y->left != T->nil) {
y->left->parent = x;
}
// 2.1.2
y->parent = x->parent;
if(x->parent == T->nil) {
T->root = y;//x是根节点
}
else if(x == x->parent->left) {
x->parent->left = y;//x是左子树
}
else{//x是右子树
x->parent->right = y;
}
// 2.1.3
y->left = x;
x->parent = y;
}
// 2.2 右旋
//把左旋的代码,x改为y,y改为x;left与right相互替换
void rbtree_right_rotate(rbtree* T, rbtree_node* y) {
rbtree_node* x = y->left;
// 2.2.1
y->left = x->right;
if (x->right != T->nil) {
x->right->parent = y;
}
// 2.2.2
x->parent = y->parent;
if (y->parent == T->nil) {
T->root = x;
}
else if (y == y->parent->right) {
y->parent->right = x;
}
else {
y->parent->left = x;
}
// 2.2.3
x->right = y;
y->parent = x;
}
// 3 插入
// 3.1 插入-比较节点的大小
int key_compare(KEY_TYPE a,KEY_TYPE b){
if(a>b){
return 1;
}else if(a<b){
return -1;
}else{
return 0;
}
}
// 3.2 插入节点,先找位置,再调整颜色
void rbtree_insert(rbtree* T,rbtree_node* z){
rbtree_node* x = T->root;
rbtree_node* y = T->nil;
// 3.2.1 通过遍历找到z应该插入的位置
while(x!=T->nil){
y = x;
if(key_compare(z->key,x->key) < 0){
//x的值更大,就找左子树
x = x->left;
}else if(key_compare(z->key,x->key) > 0){
//x的值更小,就找右子树
x = x->right;
}else{
//两者相等,根据项目的业务处理
//可能丢弃,可能通过加减后再重新排序
return ;
}
}
// 3.2.2 进行插入
z->parent = y;
if(y == T->nil){
//T树为空
T->root = z;
}else if(key_compare(z->key,y->key)<0){
//y更大,插入到左子树
y->left = z;
}else{
//y更小,插入到右子树
y->right = z;
}
z->left = T->nil;
z->right = T->nil;
z->color = RED;
// 3.2.3 维护红黑树的性质
//"如果一个节点是红色,那么它的两个子节点都是黑色"
rbtree_insert_fixup(T,z);
}
// 3.3 插入维护红黑树的性质
//"如果一个节点是红色,那么它的两个子节点都是黑色"
//六种情况
// 1. 父节点是左子树,叔节点是红色
// 2. 父节点是左子树,叔节点是黑色,当前节点是右孩子
// 3. 父节点是左子树,叔节点是黑色,当前节点是左孩子
// 4. 父节点是右子树,叔节点是红色
// 5. 父节点是右子树,叔节点是黑色,当前节点是右孩子
// 6. 父节点是右子树,叔节点是黑色,当前节点是左孩子
void rbtree_insert_fixup(rbtree* T,rbtree_node* z){
while(z->parent->color == RED){
//如果父节点是红色就需要调整
if(z->parent == z->parent->parent->left){
//如果父节点是左子树
//y是叔父节点
rbtree_node* y =z->parent->parent->right;
if(y->color == RED){
//如果叔父节点是红色 情况1
z->parent->color = BLACK;
y->color = BLACK;
z->parent->parent->color = RED;
z =z->parent->parent;
}else{
//如果叔节点是黑色
if(z == z->parent->right){
//当前节点是右孩子 情况2
z= z->parent;
rbtree_left_rotate(T,z);
}
//当前节点是左孩子,情况3
z->parent->color = BLACK;
z->parent->parent->color = RED;
rbtree_right_rotate(T,z->parent->parent);
}
}else{
//父节点是右子树
//y是叔节点
rbtree_node* y = z->parent->parent->left;
if(y->color == RED){
//叔节点是红色,情况4
z->parent->color = BLACK;
y->color = BLACK;
z->parent->parent->color = RED;
z = z->parent->parent;
}else{
//叔节点是黑色
if(z == z->parent->left){
//当前节点是左孩子,情况6
z = z->parent;
rbtree_right_rotate(T,z);
}
//当前节点是右孩子,情况5
z->parent->color = BLACK;
z->parent->parent->color= RED;
rbtree_left_rotate(T,z->parent->parent);
}
}
}
//根节点永远是黑色
T->root->color = BLACK;
}
// 4 删除
// 4.1 删除-寻找从某节点开始的最小节点
rbtree_node * rbtree_min(rbtree* T,rbtree_node* node){
//如果为哨兵节点
if(node == T->nil ) return T->nil;
while(node->left != T->nil){
node = node->left;
}
return node;
}
// 4.2 删除-寻找从某节点开始的最大节点
rbtree_node * rbtree_max(rbtree* T,rbtree_node* node){
//如果为哨兵节点
if(node == T->nil ) return T->nil;
while(node->right != T->nil){
node = node->right;
}
return node;
}
// 4.3 删除-找到node节点的可代替节点,右子树的最小值or左子树的最大值,默认为右子树的最小值
rbtree_node* rbtree_successor(rbtree* T, rbtree_node* node) {
if(node -> right != T->nil){
return rbtree_min(T,node->right);
}else if( node->left != T->nil){
return rbtree_max(T,node->left);
}
return node;
}
// 4.4 删除-调整情况罗列:
// 1. 当前结点是左孩子,其兄弟节点是红色的
// 2. 当前结点是左孩子,其兄弟节点是黑色的,而且兄弟结点的两个子结点也是黑色的
// 3. 当前结点是左孩子,其兄弟节点是黑色的,而且兄弟结点的左子树是红色,右子树是黑色的
// 4. 当前结点是左孩子,其兄弟节点是黑色的,而且兄弟结点的左子树任意颜色,右子树是红色
// 5. 当前结点是右孩子,其兄弟节点是红色的
// 6. 当前结点是右孩子,其兄弟节点是黑色的,而且兄弟结点的两个子结点也是黑色的
// 7. 当前结点是右孩子,其兄弟节点是黑色的,而且兄弟结点的左子树是黑色,右子树是红色的
// 8. 当前结点是右孩子,其兄弟节点是黑色的,而且兄弟结点的左子树红颜色,右子树任意颜色
//如果删除的节点是黑色则需要调整
void rbtree_delete_fixup(rbtree* T,rbtree_node* node){
//节点不为根节点并且节点是黑色
while((node != T->root)&&(node->color == BLACK)){
// 1. 要删除的节点是左子树
if(node == node->parent->left){
//兄弟节点bro_node
rbtree_node* bro_node = node->parent->right;
// 1.1 兄弟节点是红色,情况1
if(bro_node->color == RED){
bro_node->color = BLACK;
bro_node->parent->color = RED;
rbtree_left_rotate(T,node->parent);
bro_node = node->parent->right;
}
// 1.2 兄弟节点是黑色
// 1.2.1 兄弟节点的左子树:黑 右子树:黑 情况2
if((bro_node->left->color == BLACK)&&(bro_node->right->color == BLACK)){
bro_node->color = RED;
node = node->parent;
}else{
// 1.2.2 兄弟节点的左子树:红色 右子树:黑色 情况3
if ((bro_node->left->color == RED) && (bro_node->right->color == BLACK)) {
bro_node->left->color = BLACK;
bro_node->color = RED;
rbtree_right_rotate(T, bro_node);
bro_node = node->parent->right;
}
// 1.2.3 兄弟节点的左子树: 任意,右子树为:红色 情况4
bro_node->color = node->parent->color;
node->parent->color = BLACK;
bro_node->right->color = BLACK;
rbtree_left_rotate(T, node->parent);
node = T->root;
}
// 2. 要删除节点为右子树
} else if (node == node->parent->right) {
rbtree_node* bro_node = node->parent->left;
// 2.1 兄弟节点为:红色 情况5
if (bro_node->color == RED) {
bro_node->color = BLACK;
bro_node->parent->color = RED;
rbtree_right_rotate(T, node->parent);
bro_node = node->parent->left;
}
// 2.2 兄弟节点为:黑色
// 2.2.1 兄弟节点的左子树为:黑色,右子树为:黑色 情况6
if ((bro_node->left->color == BLACK) && (bro_node->right->color == BLACK)) {
bro_node->color = RED;
node = node->parent;
} else {
// 2.2.2兄弟节点的左子树为:黑色,右子树为:红色 情况7
if ((bro_node->left->color == BLACK) && (bro_node->right->color == RED)) {
bro_node->right->color = BLACK;
bro_node->color = RED;
rbtree_left_rotate(T, bro_node);
bro_node = node->parent->left;
}
// 2.2.3 兄弟节点的左子树为:红色,右子树为:任意 情况8
bro_node->color = node->parent->color;
node->parent->color = BLACK;
bro_node->left->color = BLACK;
rbtree_right_rotate(T, node->parent);
node = T->root;
}
}
}
node->color = BLACK;
}
// 4.5 删除
rbtree_node* rbtree_delete(rbtree* T, rbtree_node* node) {
rbtree_node* del_node = T->nil; // 真正待删除的节点
rbtree_node* son_node = T->nil; // 待删除的节点的子树
// 4.5.1 找到需要删除的节点 del_node
if ((node->left == T->nil) || (node->right == T->nil)) {
del_node = node;
} else {
//待删除节点的左右子树都不为空
//找到该待删除的节点的可代替节点,左子树的最大值or右子树的最小值
//删除该可代替节点
//并用可代替节点,覆盖真正待删除的节点
del_node = rbtree_successor(T, node);
}
// 4.5.2 删除 del_node 节点
if (del_node->left != T->nil) {
son_node = del_node->left;
} else if (del_node->right != T->nil) {
son_node = del_node->right;
}
//if (son_node != T->nil) son_node->parent = del_node->parent;
//让删除节点的子树指向删除节点的父节点
son_node->parent = del_node->parent;
if (del_node->parent == T->nil) {
T->root = son_node;
} else if (del_node == del_node->parent->left) {
del_node->parent->left = son_node;
} else if (del_node == del_node->parent->right) {
del_node->parent->right = son_node;
}
// 4.5.3 用 del_node 节点,覆盖真正待删除的node节点
if (del_node != node) {
//对应del_node = rbtree_successor(T, node);
node->key = del_node->key;
node->value = del_node->value;
}
// 4.5.4 如果正真删除的y节点为红色,则不需要进行调整;如果为黑色,则需要进行调整,以满足红黑树的性质
if (del_node->color == BLACK) {
rbtree_delete_fixup(T, son_node);
}
// 4.5.5 返回真正删除的节点
return del_node;
}
// 5. 红黑树的查找
rbtree_node* rbtree_search(rbtree* T, KEY_TYPE key) {
rbtree_node* node = T->root;
while (node != T->nil) {
if (key == node->key) return node;
else if (key > node->key) node = node->right;
else if (key < node->key) node = node->left;
}
return T->nil;
}
// 6. 红黑树的遍历 中序遍历 左根右
void rbtree_traversal(rbtree* T, rbtree_node* node) {
if (node != T->nil) {
rbtree_traversal(T, node->left);
printf("key: %d, color: %d\n", node->key, node->color);
rbtree_traversal(T, node->right);
}
}
// 7. main测试
int main() {
int keys[20] = {24,25,13,35,23, 26,67,47,38,98, 20,19,17,49,12, 21,9,18,14,15};
// 7.1 初始化 T
rbtree* T = (rbtree*)malloc(sizeof(rbtree));
if (T == NULL) {
printf("malloc fail\n");
return 1;
}
T->nil = (rbtree_node*)malloc(sizeof(rbtree_node));
T->nil->color = BLACK;
T->root = T->nil;
// 7.2 插入 node
for (int i = 0; i < 20; ++i) {
rbtree_node* node = (rbtree_node*)malloc(sizeof(rbtree_node));
node->key = keys[i];
node->value = NULL;
rbtree_insert(T, node);
}
rbtree_traversal(T, T->root);
printf("----------------------------------------\n");
// 7.3 删除node
for (int i = 0; i < 20; ++i) {
rbtree_node* node = rbtree_search(T, keys[i]);
rbtree_node* cur = rbtree_delete(T, node);
free(cur);
rbtree_traversal(T, T->root);
printf("----------------------------------------\n");
}
// 释放哨兵节点
free(T->nil);
// 释放红黑树结构体
free(T);
return 0;
}
更多推荐

所有评论(0)