目录
1.红黑树的特点
首先是一颗二叉搜索树(所有的左子树小于根,所有的右子树大于根),但在这个基础上引入了红河两种颜色,相当于给每个节点打上flag,后续动态平衡时起到非常重要的作用,针对颜色而言;其中根结点和叶子(NULL)节点必须是黑色的,红色结点的左右孩子必须是黑色的,也就是不可以存在连续的两个红色结点,从任意结点到叶所有的路径上黑色的结点数量必须是相同的。

如下是红黑树的数据结构定义
#define RED 1
#define BLACK 2
typedef int DataType;
typedef struct rbtreenode {
DataType data;
void* value;
unsigned char color;
struct rbtreenode* left; //左孩子
struct rbtreenode* right; //右孩子
struct rbtreenode* parent;//父结点
}RBTreeNode;
typedef struct rbtree {
RBTreeNode* nil; //叶子(NULL)
RBTreeNode* root; //根
}RBTree;
RBTree* InitRBTree() {
RBTree* T = (RBTree *)malloc(sizeof(RBTree));
if (!T) return;
T->nil = (RBTreeNode *)malloc(sizeof(RBTreeNode));
if (!T->nil) return;
T->nil->color = BLACK;
T->root = T->nil;
return T;
}
RBTreeNode* InitRBTreeNode() {
RBTreeNode* node = (RBTreeNode*)malloc(sizeof(RBTreeNode));
if (!node) return;
node->value = NULL;
return node;
}
2.红黑树的旋转
左旋(Left Rotation)以及 右旋(Right Rotation)

/*
* left rotate right rotate
* x->left=a x->right=y y->left=b y->right=c
* y->left=x y->right=c x->left=a x->right=b
*/
void rbtree_left_rotate(RBTree *T,RBTreeNode *x) {
RBTreeNode* y = x->right;
x->right = y->left;
if (y->left != T->nil) {
y->left->parent = x;
}
y->parent = x->parent;
if (x->parent == T->nil) {
T->root = y;
}
else if (x == x->parent->left) {
x->parent->left = y;
}
else {
x->parent->right = y;
}
y->left = x;
x->parent = y;
}
void rbtree_right_rotate(RBTree* T, RBTreeNode* y) {
RBTreeNode* x = y->left;
y->left = x->right;
if (x->right != T->nil) {
x->right->parent = y;
}
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;
}
x->right = y;
y->parent = x;
}
3.红黑树的插入
红黑树规定,插入的节点必须是红色的。而且,二叉查找树中新插入的节点都是放在叶子节点上,方法相对常规。
void rbtree_insert(RBTree *T,RBTreeNode *z) {
RBTreeNode* y = T->nil;
RBTreeNode* x = T->root;
while (x != T->nil) {
y = x;
if (z->data < x->data) {
x = x->left;
}
else if (z->data > x->data) {
x = x->right;
}
else break;
}
z->parent = y;
if (y == T->nil) {
T->root = z;
}
else if (z->data < y->data) {
y->left = z;
}
else {
y->right = z;
}
z->color = RED;
z->left = z->right = T->nil;
rbtree_insert_fixup(T, z);
}
4.红黑树的插入维护(重点)
1.插入节点的叔叔节点是红色的 父节点和叔叔节点变成黑色 爷爷节点变成红色 下次迭代从爷爷节点开始

2.叔叔节点是黑色 插入节点是父节点的左孩子 父亲节点变成黑色 爷爷节点变成红色 最后绕着爷爷节点做一次右旋

3.叔叔节点是黑色 插入节点是父节点的右孩子 绕着父节点做一次左旋 父亲节点变成黑色 爷爷节点变成红色 最后绕着爷爷节点做一次右旋

/* 插入后维护
* 1.插入节点的叔叔节点是红色的
* 父节点和叔叔节点变成黑色 爷爷节点变成红色 下次迭代从爷爷节点开始
* 2.叔叔节点是黑色 插入节点是父节点的左孩子
* 父亲节点变成黑色 爷爷节点变成红色 最后绕着爷爷节点做一次右旋
* 3.叔叔节点是黑色 插入节点是父节点的右孩子
* 绕着父节点做一次左旋
* 父亲节点变成黑色 爷爷节点变成红色 最后绕着爷爷节点做一次右旋
*/
void rbtree_insert_fixup(RBTree* T, RBTreeNode* z) {
while (z->parent->color == RED) {
if (z->parent == z->parent->parent->left) {
//叔叔节点拿出来
RBTreeNode* y = z->parent->parent->right;
if (y->color == RED) {
y->color = z->parent->color = BLACK;
z->parent->parent->color = RED;
z = z->parent->parent;
}
else {
if (z == z->parent->right) {
z = z->parent;
rbtree_left_rotate(T, z);
}
z->parent->color = BLACK;
z->parent->parent->color = RED;
rbtree_right_rotate(T, z->parent->parent);
}
}
else {
RBTreeNode* y = z->parent->parent->left;
if (y->color == RED) {
z->parent->color = y->color = BLACK;
z->parent->parent->color = RED;
z = z->parent->parent;
}
else {
if (z == z->parent->left) {
z = z->parent;
rbtree_right_rotate(T, z);
}
z->parent->color = BLACK;
z->parent->parent->color = RED;
rbtree_left_rotate(T,z->parent->parent);
}
}
}
T->root->color = BLACK;
}
5.红黑树的删除
//delrbtree
/*
* 红黑树的删除操作根据儿子节点的孩子节点个数,分为三种情况
* 1.没有孩子 即为叶结点。直接把父结点的对应儿子指针设为NULL就可以了.
* 2.1个孩子 把父结点的相应儿子指针指向儿子的孩子,然后删除儿子节点就可以了.
* 3.2个孩子 用后继节点替换待删除的节点,然后删除这个后继节点,问题就转化成了上述两点
*/
RBTreeNode* rbtree_mini(RBTree* T, RBTreeNode* x) {
while (x->left != T->nil) {
x = x->left;
}
return x;
}
RBTreeNode* rbtree_count(RBTree* T, RBTreeNode* x) {
RBTreeNode* y = x->parent;
if (x->right != T->nil) {
return rbtree_mini(T,x->right);
}
return y;
}
RBTreeNode* rbtree_delete(RBTree *T,RBTreeNode *z) {
RBTreeNode* y = T->nil;
RBTreeNode* x = T->nil;
if (z->left == T->nil || z->right ==T->nil) {
y = z;
}
else {
y = rbtree_count(T, z);
}
if (y->left != T->nil) {
x = y->left;
}
else if (y->right != T->nil) {
x = y->right;
}
x->parent = y->parent;
if (y->parent == T->nil) {
T->root = x;
}
else if (y == y->parent->left) {
y->parent->left = x;
}
else {
y->parent->right = y;
}
if (y !=z ) {
z->data = y->data;
z->value = y->value;
}
if (y->color == BLACK) {
rbtree_delete_fixup(T,x);
}
return y;
}
6.红黑树的删除维护(重点)
1.x的兄弟节点w是红色的
* 将w涂黑,将x->p涂红,然后把兄弟节点绕着父节点左旋,
* 最后把w重新做指向,令w=x->p->right,
* 这样w变成了黑色结点(根据红黑树的性质,必定是黑色的),
* 调整结束以后,情况1可能会变成情况2、3、4.

* 2.x的兄弟w是黑色的,且w的两个儿子都是黑色
* 直接把兄弟节点变成红色,再将指向x的指针指向父节点,
* 然后根据父亲节点的颜色决定是否进行下一步调整,如果父亲节点的颜色为红色,
* 就把父亲节点变成黑色,即可结束调整;如果父亲节点的颜色是黑色,
* 那就要根据调整结束后的状态做下一步调整,可能会变成情况1、2、3、4.

* 3.x的兄弟w是黑色的,而w的左孩子为红色,右孩子为黑色
* 那么我们将w->left涂黑,然后将w涂红,再将w->left绕着w做右旋,然后情况3就会变成情况4.

* 4.x的兄弟w是黑色的,而w的左孩子为黑色,右孩子为红色
* 把兄弟节点w换成父节点的颜色,并把父亲节点和w-right涂黑,然后把兄弟节点w绕着父节点做一次左旋,
* 完成之后的结构刚好满足红黑树的性质.

/*
* 删除后维护
* 1.x的兄弟节点w是红色的
* 将w涂黑,将x->p涂红,然后把兄弟节点绕着父节点左旋,
* 最后把w重新做指向,令w=x->p->right,
* 这样w变成了黑色结点(根据红黑树的性质,必定是黑色的),
* 调整结束以后,情况1可能会变成情况2、3、4.
*
* 2.x的兄弟w是黑色的,且w的两个儿子都是黑色
* 直接把兄弟节点变成红色,再将指向x的指针指向父节点,
* 然后根据父亲节点的颜色决定是否进行下一步调整,如果父亲节点的颜色为红色,
* 就把父亲节点变成黑色,即可结束调整;如果父亲节点的颜色是黑色,
* 那就要根据调整结束后的状态做下一步调整,可能会变成情况1、2、3、4.
*
* 3.x的兄弟w是黑色的,而w的左孩子为红色,右孩子为黑色
* 那么我们将w->left涂黑,然后将w涂红,再将w->left绕着w做右旋,然后情况3就会变成情况4.
*
* 4.x的兄弟w是黑色的,而w的左孩子为黑色,右孩子为红色
* 把兄弟节点w换成父节点的颜色,并把父亲节点和w-right涂黑,然后把兄弟节点w绕着父节点做一次左旋,
* 完成之后的结构刚好满足红黑树的性质.
*/
void rbtree_delete_fixup(RBTree* T, RBTreeNode* x) {
while ((x != T->root) && (x->color == BLACK)) {
// 此if与相应的else是镜像的
if (x == x->parent->left) {
// 找到兄弟节点
RBTreeNode* w = x->parent->right;
// 情况1:兄弟节点为红色
if (w->color == RED) {
// 兄弟节点变成黑色
w->color = BLACK;
// 父节点变成红色
x->parent->color = RED;
// 父节点做左旋
rbtree_left_rotate(T, x->parent);
// 重新设置x的兄弟节点
w = x->parent->right;
}
// 情况2:兄弟节点是黑色的,且兄弟的左孩子和右孩子都是黑色
if ((w->left->color == BLACK) && (w->right->color == BLACK)) {
// 兄弟节点变成红色
w->color = RED;
// 将指向x的指针指向其父节点
x = x->parent;
}
else {
// 情况3:x的兄弟节点是黑色的,兄弟的左孩子是红色,右孩子是黑色
if (w->right->color == BLACK) {
// 将左孩子涂黑
w->left->color = BLACK;
// 将兄弟节点变红
w->color = RED;
// 对兄弟节点右旋
rbtree_right_rotate(T, w);
// 重新设置x的兄弟节点
w = x->parent->right;
}
// 情况4:x的兄弟节点是黑色;x的兄弟节点的右孩子是红色的
// 将兄弟节点换成父节点的颜色
w->color = x->parent->color;
// 把父节点和兄弟节点的右孩子涂黑
x->parent->color = BLACK;
w->right->color = BLACK;
// 对父节点做左旋
rbtree_left_rotate(T, x->parent);
// 设置x指针,指向根节点
x = T->root;
}
}
else {
RBTreeNode* w = x->parent->left;
if (w->color == RED) {
w->color = BLACK;
x->parent->color = RED;
rbtree_right_rotate(T, x->parent);
w = x->parent->left;
}
if ((w->left->color == BLACK) && (w->right->color == BLACK)) {
w->color = RED;
x = x->parent;
}
else {
if (w->left->color == BLACK) {
w->right->color = BLACK;
w->color = RED;
rbtree_left_rotate(T, w);
w = x->parent->left;
}
w->color = x->parent->color;
x->parent->color = BLACK;
w->left->color = BLACK;
rbtree_right_rotate(T, x->parent);
x = T->root;
}
}
}
// 继承节点变为黑色,为了弥补失去的黑高
x->color = BLACK;
}
7.源代码
#include <stdio.h>
#include <stdlib.h>
//RED BLACK TREE
/*
* 节点是红色或者黑色
* 根是黑色的
* 所有叶子都是黑色的,并且是NIL节点
* 每个红色节点的两个子节点都是黑色的
* 并且红色的叶子结点不能连续
* 从任意一个节点到其每个叶子的路径黑色节点都相同
*/
#define RED 1
#define BLACK 2
typedef int DataType;
typedef struct rbtreenode {
DataType data;
void* value;
unsigned char color;
struct rbtreenode* left; //左孩子
struct rbtreenode* right; //右孩子
struct rbtreenode* parent;//父结点
}RBTreeNode;
typedef struct rbtree {
RBTreeNode* nil; //叶子(NULL)
RBTreeNode* root; //根
}RBTree;
RBTree* InitRBTree() {
RBTree* T = (RBTree *)malloc(sizeof(RBTree));
if (!T) return;
T->nil = (RBTreeNode *)malloc(sizeof(RBTreeNode));
if (!T->nil) return;
T->nil->color = BLACK;
T->root = T->nil;
return T;
}
RBTreeNode* InitRBTreeNode() {
RBTreeNode* node = (RBTreeNode*)malloc(sizeof(RBTreeNode));
if (!node) return;
node->value = NULL;
return node;
}
/*
* left rotate right rotate
* x->left=a x->right=y y->left=b y->right=c
* y->left=x y->right=c x->left=a x->right=b
*/
void rbtree_left_rotate(RBTree *T,RBTreeNode *x) {
RBTreeNode* y = x->right;
x->right = y->left;
if (y->left != T->nil) {
y->left->parent = x;
}
y->parent = x->parent;
if (x->parent == T->nil) {
T->root = y;
}
else if (x == x->parent->left) {
x->parent->left = y;
}
else {
x->parent->right = y;
}
y->left = x;
x->parent = y;
}
void rbtree_right_rotate(RBTree* T, RBTreeNode* y) {
RBTreeNode* x = y->left;
y->left = x->right;
if (x->right != T->nil) {
x->right->parent = y;
}
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;
}
x->right = y;
y->parent = x;
}
/* 插入后维护
* 1.插入节点的叔叔节点是红色的
* 父节点和叔叔节点变成黑色 爷爷节点变成红色 下次迭代从爷爷节点开始
* 2.叔叔节点是黑色 插入节点是父节点的左孩子
* 父亲节点变成黑色 爷爷节点变成红色 最后绕着爷爷节点做一次右旋
* 3.叔叔节点是黑色 插入节点是父节点的右孩子
* 绕着父节点做一次左旋
* 父亲节点变成黑色 爷爷节点变成红色 最后绕着爷爷节点做一次右旋
*/
void rbtree_insert_fixup(RBTree* T, RBTreeNode* z) {
while (z->parent->color == RED) {
if (z->parent == z->parent->parent->left) {
//叔叔节点拿出来
RBTreeNode* y = z->parent->parent->right;
if (y->color == RED) {
y->color = z->parent->color = BLACK;
z->parent->parent->color = RED;
z = z->parent->parent;
}
else {
if (z == z->parent->right) {
z = z->parent;
rbtree_left_rotate(T, z);
}
z->parent->color = BLACK;
z->parent->parent->color = RED;
rbtree_right_rotate(T, z->parent->parent);
}
}
else {
RBTreeNode* y = z->parent->parent->left;
if (y->color == RED) {
z->parent->color = y->color = BLACK;
z->parent->parent->color = RED;
z = z->parent->parent;
}
else {
if (z == z->parent->left) {
z = z->parent;
rbtree_right_rotate(T, z);
}
z->parent->color = BLACK;
z->parent->parent->color = RED;
rbtree_left_rotate(T,z->parent->parent);
}
}
}
T->root->color = BLACK;
}
void rbtree_insert(RBTree *T,RBTreeNode *z) {
RBTreeNode* y = T->nil;
RBTreeNode* x = T->root;
while (x != T->nil) {
y = x;
if (z->data < x->data) {
x = x->left;
}
else if (z->data > x->data) {
x = x->right;
}
else break;
}
z->parent = y;
if (y == T->nil) {
T->root = z;
}
else if (z->data < y->data) {
y->left = z;
}
else {
y->right = z;
}
z->color = RED;
z->left = z->right = T->nil;
rbtree_insert_fixup(T, z);
}
//*******************************************************************************
/*
* 删除后维护
* 1.x的兄弟节点w是红色的
* 将w涂黑,将x->p涂红,然后把兄弟节点绕着父节点左旋,
* 最后把w重新做指向,令w=x->p->right,
* 这样w变成了黑色结点(根据红黑树的性质,必定是黑色的),
* 调整结束以后,情况1可能会变成情况2、3、4.
*
* 2.x的兄弟w是黑色的,且w的两个儿子都是黑色
* 直接把兄弟节点变成红色,再将指向x的指针指向父节点,
* 然后根据父亲节点的颜色决定是否进行下一步调整,如果父亲节点的颜色为红色,
* 就把父亲节点变成黑色,即可结束调整;如果父亲节点的颜色是黑色,
* 那就要根据调整结束后的状态做下一步调整,可能会变成情况1、2、3、4.
*
* 3.x的兄弟w是黑色的,而w的左孩子为红色,右孩子为黑色
* 那么我们将w->left涂黑,然后将w涂红,再将w->left绕着w做右旋,然后情况3就会变成情况4.
*
* 4.x的兄弟w是黑色的,而w的左孩子为黑色,右孩子为红色
* 把兄弟节点w换成父节点的颜色,并把父亲节点和w-right涂黑,然后把兄弟节点w绕着父节点做一次左旋,
* 完成之后的结构刚好满足红黑树的性质.
*/
void rbtree_delete_fixup(RBTree* T, RBTreeNode* x) {
while ((x != T->root) && (x->color == BLACK)) {
// 此if与相应的else是镜像的
if (x == x->parent->left) {
// 找到兄弟节点
RBTreeNode* w = x->parent->right;
// 情况1:兄弟节点为红色
if (w->color == RED) {
// 兄弟节点变成黑色
w->color = BLACK;
// 父节点变成红色
x->parent->color = RED;
// 父节点做左旋
rbtree_left_rotate(T, x->parent);
// 重新设置x的兄弟节点
w = x->parent->right;
}
// 情况2:兄弟节点是黑色的,且兄弟的左孩子和右孩子都是黑色
if ((w->left->color == BLACK) && (w->right->color == BLACK)) {
// 兄弟节点变成红色
w->color = RED;
// 将指向x的指针指向其父节点
x = x->parent;
}
else {
// 情况3:x的兄弟节点是黑色的,兄弟的左孩子是红色,右孩子是黑色
if (w->right->color == BLACK) {
// 将左孩子涂黑
w->left->color = BLACK;
// 将兄弟节点变红
w->color = RED;
// 对兄弟节点右旋
rbtree_right_rotate(T, w);
// 重新设置x的兄弟节点
w = x->parent->right;
}
// 情况4:x的兄弟节点是黑色;x的兄弟节点的右孩子是红色的
// 将兄弟节点换成父节点的颜色
w->color = x->parent->color;
// 把父节点和兄弟节点的右孩子涂黑
x->parent->color = BLACK;
w->right->color = BLACK;
// 对父节点做左旋
rbtree_left_rotate(T, x->parent);
// 设置x指针,指向根节点
x = T->root;
}
}
else {
RBTreeNode* w = x->parent->left;
if (w->color == RED) {
w->color = BLACK;
x->parent->color = RED;
rbtree_right_rotate(T, x->parent);
w = x->parent->left;
}
if ((w->left->color == BLACK) && (w->right->color == BLACK)) {
w->color = RED;
x = x->parent;
}
else {
if (w->left->color == BLACK) {
w->right->color = BLACK;
w->color = RED;
rbtree_left_rotate(T, w);
w = x->parent->left;
}
w->color = x->parent->color;
x->parent->color = BLACK;
w->left->color = BLACK;
rbtree_right_rotate(T, x->parent);
x = T->root;
}
}
}
// 继承节点变为黑色,为了弥补失去的黑高
x->color = BLACK;
}
//*******************************************************************************
//delrbtree
/*
* 红黑树的删除操作根据儿子节点的孩子节点个数,分为三种情况
* 1.没有孩子 即为叶结点。直接把父结点的对应儿子指针设为NULL就可以了.
* 2.1个孩子 把父结点的相应儿子指针指向儿子的孩子,然后删除儿子节点就可以了.
* 3.2个孩子 用后继节点替换待删除的节点,然后删除这个后继节点,问题就转化成了上述两点
*/
RBTreeNode* rbtree_mini(RBTree* T, RBTreeNode* x) {
while (x->left != T->nil) {
x = x->left;
}
return x;
}
RBTreeNode* rbtree_count(RBTree* T, RBTreeNode* x) {
RBTreeNode* y = x->parent;
if (x->right != T->nil) {
return rbtree_mini(T,x->right);
}
return y;
}
RBTreeNode* rbtree_delete(RBTree *T,RBTreeNode *z) {
RBTreeNode* y = T->nil;
RBTreeNode* x = T->nil;
if (z->left == T->nil || z->right ==T->nil) {
y = z;
}
else {
y = rbtree_count(T, z);
}
if (y->left != T->nil) {
x = y->left;
}
else if (y->right != T->nil) {
x = y->right;
}
x->parent = y->parent;
if (y->parent == T->nil) {
T->root = x;
}
else if (y == y->parent->left) {
y->parent->left = x;
}
else {
y->parent->right = y;
}
if (y !=z ) {
z->data = y->data;
z->value = y->value;
}
if (y->color == BLACK) {
rbtree_delete_fixup(T,x);
}
return y;
}
RBTreeNode* rbtree_search(RBTree* T, DataType data) {
RBTreeNode* node = T->root;
while (node != T->nil) {
if (data < node->data) {
node = node->left;
}
else if (data > node->data) {
node = node->right;
}
else {
return node;
}
}
return T->nil;
}
void rbtree_leader(RBTree* T, RBTreeNode* node) {
if (node != T->nil) {
printf("data = %d color = %d\n", node->data, node->color);
rbtree_leader(T, node->left);
rbtree_leader(T, node->right);
}
}
void rbtree_inorder(RBTree *T,RBTreeNode *node) {
if (node != T->nil) {
rbtree_inorder(T, node->left);
printf("data = %d color = %d\n",node->data,node->color);
rbtree_inorder(T, node->right);
}
}
void rbtree_lastder(RBTree* T, RBTreeNode* node) {
if (node != T->nil) {
rbtree_lastder(T, node->left);
rbtree_lastder(T, node->right);
printf("data = %d color = %d\n", node->data, node->color);
}
}
int main() {
int keyArray[20] = { 24,25,13,35,23, 26,67,47,38,98, 20,19,17,49,12, 21,9,18,14,15 };
RBTree* T = InitRBTree();
for (int i = 0; i<sizeof(keyArray)/sizeof(keyArray[0]); ++i) {
RBTreeNode* node = InitRBTreeNode();
node->data = keyArray[i];
rbtree_insert(T,node);
}
rbtree_inorder(T,T->root);
printf("----------------------------------------\n");
RBTreeNode* node = rbtree_search(T, 23);
RBTreeNode* cur = rbtree_delete(T, node);
free(cur);
rbtree_inorder(T, T->root);
return 0;
}
2967

被折叠的 条评论
为什么被折叠?



