红黑树性质
- 每个结点是红的或者黑的
- 根结点是黑的
- 每个叶子结点是黑的
- 如果一个结点是红的,则它的两个儿子都是黑的
- 对每个结点,从该结点到其子孙结点的所有路径上包含相同数目的黑结点
定义红黑树
typedef int KEY_TYPE;
#define RBTREE_ENTRY(name, type) \
struct name { \
struct type *right; /*因为红黑树也是二叉树,所以定义左右子树*/ \
struct type *left; \
struct type *parent; /*在做红黑树调整时候需要用到*/ \
unsigned char color; /*定义结点是红色还是黑色*/ \
}
// 定义结点结构
typedef struct _rbtree_node {
KEY_TYPE key; // 红黑树主要用于查找的,因此定义key和value
void *value;
RBTREE_ENTRY(, _rbtree_node) node;
} rbtree_node;
// 定义红黑树
typedef struct _rbtree {
struct _rbtree_node *root;
struct _rbtree_node *nil;
} rbtree;
红黑树旋转
当红黑树性质被破坏时候需要进行旋转,分为左旋和右旋,左旋与右旋不需要改变颜色。
实现左旋
在该结构基础上进行左旋
void rbtree_left_rotate(rbtree *T, rbtree_node *x) {
rbtree_node *y = x->node->right;
// 需要同时改变两个指针的指向
x->node->right = y->node->left; // x的右结点为b
if (y->node->left->node != T->nil) {
// 不是叶子结点才进行父节点指向的改变
y->node->left->node->parent = x; // y的左结点的父节点变为x
}
y->node->parent = x->node->parent;
if (x->node->parent == T->nil) {
// 如果x为根节点
T->root = y;
} else if (x == x->node->parent->node->left) {
// x是其parent结点的左子树
x->node->parent->node->left = y;
} else {
// x是其parent结点的右子树
x->node->parent->node->right = y;
}
y->node->left = x;
x->node->parent = y;
}
实现右旋
在该结构上进行右旋
如果左旋实现好的话,右旋实现会很方便,只要将左旋代码复制,然后将left改为right,right改为left,x改为y,y改为x即可
void rbtree_right_rotate(rbtree *T, rbtree_node *y) {
rbtree_node *x = y->node->left;
// 需要同时改变两个指针的指向
y->node->left = x->node->right;
if (x->node->right->node != T->nil) {
// 不是叶子结点才进行父节点指向的改变
x->node->right->node->parent = y;
}
x->node->parent = y->node->parent;
if (x->node->parent == T->nil) {
T->root = x;
} else if (y == y->node->parent->node->right) {
y->node->parent->node->right = x;
} else {
y->node->parent->node->left = x;
}
x->node->right = y;
y->node->parent = x;
}
插入数据
红黑树中插入结点会添加到树的最底层
void rbtree_insert_fixup(rbtree *T, rbtree_node *z) {
// 调整红黑树的函数
while(z->node->parent->node->color == RED) {
// z自己是红色,父节点也是红色,祖父结点是黑色,叔父结点颜色不确定
if (z->node->parent == z->node->parent->node->parent->node->left) {
// 如果z的父节点是祖父结点的左子树
rbtree_node *y = z->node->parent->node->parent->node->right; // 获得叔父结点
if(y->node->color == RED) {
// 如果叔父结点颜色为红色
z->node->parent->node->parent->node->color = RED; // 将祖父结点变为红色
y->node->color = BLACK; // 叔父结点变为黑色
z->node->parent->node->color = BLACK; // 将父节点变为黑色
z = z->node->parent->node->parent; // z始终为红色,进行递归改变颜色
} else {
// 如果叔父结点为黑色
if (z == z->node->parent->node->right) {
z = z->node->parent;
rbtree_left_rotate(T, z); // 先进性左旋,会得到一个中间状态,该状态不满足红黑树的定义,需要再进行一次变换
}
if (z == z->node->parent->node->left) {
// 左边比较重
z->node->parent->node->color = BLACK;
z->node->parent->node->parent->node->color = RED;
// 以祖父结点进行右旋
rbtree_right_rotate(T, z->node->parent->node->parent->node);
}
}
} else {
}
}
}
void rbtree_insert(rbtree *T, rbtree_node *z) {
rbtree_node *x = T->root;
rbtree_node *y = T->nil;
while(x != T->nil) {
y = x; // y始终比x高一级
if (z->key < x->key) {
x = x->node->left;
} else if (z->key > x->key) {
x = x->node->right;
} else {
// key相等,红黑树定义中没有关于key相等的话如何处理,可以根据自己的业务进行处理
return;
}
}
// 如果红黑树一个结点也没有
if (y == T->nil) {
T->root = z;
}
// 将z插入到y的左子树还是右子树
if (y->key > z->key) {
// 插入到y的左子树上
y->node->left = z;
} else {
y->node->right = z;
}
// 修改下插入的z结点的属性
z->node->parent = y;
z->node->left = T->nil;
z->node->right = T->nil;
// 红黑树在插入结点之前已经是红黑树了
z->node->color = RED; // 上红色,定义为红色第四条性质可能不满足,其他的几个条件满足,然后调整红黑树
rbtree_insert_fixup(T, z);
}
完整代码
#define RED 0
#define BLACK 1
typedef int KEY_TYPE;
#define RBTREE_ENTRY(name, type) \
struct name { \
struct type *right; /*因为红黑树也是二叉树,所以定义左右子树*/ \
struct type *left; \
struct type *parent; /*在做红黑树调整时候需要用到*/ \
unsigned char color; /*定义结点是红色还是黑色*/ \
}
// 定义结点结构
typedef struct _rbtree_node {
KEY_TYPE key; // 红黑树主要用于查找的,因此定义key和value
void *value;
RBTREE_ENTRY(, _rbtree_node) *node;
} rbtree_node;
// 定义红黑树
typedef struct _rbtree {
struct _rbtree_node *root; // 根节点
struct _rbtree_node *nil; // 叶子结点
} rbtree;
// 左旋
void rbtree_left_rotate(rbtree *T, rbtree_node *x) {
rbtree_node *y = x->node->right;
// 需要同时改变两个指针的指向
x->node->right = y->node->left; // x的右结点为b
if (y->node->left->node != T->nil) {
// 不是叶子结点才进行父节点指向的改变
y->node->left->node->parent = x; // y的左结点的父节点变为x
}
y->node->parent = x->node->parent;
if (x->node->parent == T->nil) {
// 如果x为根节点
T->root = y;
} else if (x == x->node->parent->node->left) {
// x是其parent结点的左子树
x->node->parent->node->left = y;
} else {
// x是其parent结点的右子树
x->node->parent->node->right = y;
}
y->node->left = x;
x->node->parent = y;
}
// 右旋
void rbtree_right_rotate(rbtree *T, rbtree_node *y) {
rbtree_node *x = y->node->left;
// 需要同时改变两个指针的指向
y->node->left = x->node->right;
if (x->node->right->node != T->nil) {
// 不是叶子结点才进行父节点指向的改变
x->node->right->node->parent = y;
}
x->node->parent = y->node->parent;
if (x->node->parent == T->nil) {
T->root = x;
} else if (y == y->node->parent->node->right) {
y->node->parent->node->right = x;
} else {
y->node->parent->node->left = x;
}
x->node->right = y;
y->node->parent = x;
}
// 插入数据
void rbtree_insert_fixup(rbtree *T, rbtree_node *z) {
// 调整红黑树的函数
while(z->node->parent->node->color == RED) {
// z自己是红色,父节点也是红色,祖父结点是黑色,叔父结点颜色不确定
if (z->node->parent == z->node->parent->node->parent->node->left) {
// 如果z的父节点是祖父结点的左子树
rbtree_node *y = z->node->parent->node->parent->node->right; // 获得叔父结点
if(y->node->color == RED) {
// 如果叔父结点颜色为红色
z->node->parent->node->parent->node->color = RED; // 将祖父结点变为红色
y->node->color = BLACK; // 叔父结点变为黑色
z->node->parent->node->color = BLACK; // 将父节点变为黑色
z = z->node->parent->node->parent; // z始终为红色,进行递归改变颜色
} else {
// 如果叔父结点为黑色
if (z == z->node->parent->node->right) {
z = z->node->parent;
rbtree_left_rotate(T, z); // 先进性左旋,会得到一个中间状态,该状态不满足红黑树的定义,需要再进行一次变换
}
if (z == z->node->parent->node->left) {
// 左边比较重
z->node->parent->node->color = BLACK;
z->node->parent->node->parent->node->color = RED;
// 以祖父结点进行右旋
rbtree_right_rotate(T, z->node->parent->node->parent->node);
}
}
} else {
}
}
}
void rbtree_insert(rbtree *T, rbtree_node *z) {
rbtree_node *x = T->root;
rbtree_node *y = T->nil;
while(x != T->nil) {
y = x; // y始终比x高一级
if (z->key < x->key) {
x = x->node->left;
} else if (z->key > x->key) {
x = x->node->right;
} else {
// key相等,红黑树定义中没有关于key相等的话如何处理,可以根据自己的业务进行处理
return;
}
}
// 如果红黑树一个结点也没有
if (y == T->nil) {
T->root = z;
}
// 将z插入到y的左子树还是右子树
if (y->key > z->key) {
// 插入到y的左子树上
y->node->left = z;
} else {
y->node->right = z;
}
// 修改下插入的z结点的属性
z->node->parent = y;
z->node->left = T->nil;
z->node->right = T->nil;
// 红黑树在插入结点之前已经是红黑树了
z->node->color = RED; // 上红色,定义为红色第四条性质可能不满足,其他的几个条件满足,然后调整红黑树
rbtree_insert_fixup(T, z);
}