void rb_erase(struct rb_node *node, struct rb_root *root)
{ //删除节点node
struct rb_node *child, *parent;
int color;
if (!node->rb_left) //删除节点无左子树
child = node->rb_right;
else if (!node->rb_right) //删除节点无右子树
child = node->rb_left;
else //左右子树都有
{
struct rb_node *old = node, *left;
node = node->rb_right;
while ((left = node->rb_left) != NULL)
node = left; //node的前驱替换
if (rb_parent(old)) {
if (rb_parent(old)->rb_left == old)
rb_parent(old)->rb_left = node;
else
rb_parent(old)->rb_right = node;
} else
root->rb_node = node;
child = node->rb_right;
parent = rb_parent(node);
color = rb_color(node);
if (parent == old) {
parent = node;
} else {
if (child)
rb_set_parent(child, parent);
parent->rb_left = child;
node->rb_right = old->rb_right;
rb_set_parent(old->rb_right, node);
}
node->rb_parent_color = old->rb_parent_color;
node->rb_left = old->rb_left;
rb_set_parent(old->rb_left, node);
goto color;
}
parent = rb_parent(node);
color = rb_color(node);
if (child)
rb_set_parent(child, parent);
if (parent)
{
if (parent->rb_left == node)
parent->rb_left = child;
else
parent->rb_right = child;
}
else
root->rb_node = child;
color:
if (color == RB_BLACK) //如果删除节点为黑色则调用__rb_erase_color
__rb_erase_color(child, parent, root);
}
红黑树是一种在插入或删除结点时都需要维持平衡的二叉查找树,并且每个结点都具有颜色属性:
(1)、一个结点要么是红色的,要么是黑色的。
(2)、根结点是黑色的。
(3)、如果一个结点是红色的,那么它的子结点必须是黑色的,也就是说在沿着从根结点出发的任何路径上都不会出现两个连续的红色结点。
(4)、从一个结点到一个NULL指针的每条路径上必须包含相同数目的黑色结点。
Linux内核中的红黑树实现代码在Linux-2.6.39 /include/linux/rbtree.h和/lib/rbtree.c文件中
1、头文件
struct rb_node
{
unsigned long rb_parent_color;
#define RB_RED 0
#define RB_BLACK 1
struct rb_node *rb_right;
struct rb_node *rb_left;
} __attribute__((aligned(sizeof(long))));
操作rb_parent_color的函数,rb_parent_color成员8个字节,同时存储双亲节点地址和此节点的颜色,每个节点的bit[0]用来存储节点颜色属性,后面的存储双亲节点地址。
#define rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~3)) //获得双亲节点地址
#define rb_color(r) ((r)->rb_parent_color & 1) //获得颜色
#define rb_is_red(r) (!rb_color(r)) //判断是否为红
#define rb_is_black(r) rb_color(r) //判断是否为黑
#define rb_set_red(r) do { (r)->rb_parent_color &= ~1; } while (0) //设置红节点
#define rb_set_black(r) do { (r)->rb_parent_color |= 1; } while (0) //设置黑节点
static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
{
rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p;
//设置双亲节点地址为p
}
static inline void rb_set_color(struct rb_node *rb, int color)
{
rb->rb_parent_color = (rb->rb_parent_color & ~1) | color; //设置节点颜色
}
static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
struct rb_node ** rb_link) //初始化新节点
{
node->rb_parent_color = (unsigned long )parent;
node->rb_left = node->rb_right = NULL;
*rb_link = node;
}
struct rb_root
{
struct rb_node *rb_node; //根节点的指针
};
#define RB_ROOT (struct rb_root) { NULL, } //初始化指向根节点的指针
#define rb_entry(ptr, type, member) container_of(ptr, type, member)
//获取包含struct rb_node结构体的首地址
#define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL) //判断树是否为空
#define RB_EMPTY_NODE(node) (rb_parent(node) == node)
//判断node双亲是否为自身,树是否为空
#define RB_CLEAR_NODE(node) (rb_set_parent(node, node))
//设置node双亲节点为自身,清空树
2、插入
插入一个新节点后,为了满足红黑树颜色性质,保持树的平衡,要根据情况做出相应调整
函数rb_insert_color使用while循环不断查找双亲节点,判断属性颜色
若双亲为红色
1)双亲节点是祖父左子树的根,则
a:存在叔叔节点,颜色为红色,直接改变颜色
b:node为双亲节点右子树,则左旋,然后执行c
c:当node是双亲节点左子树
2)当双亲节点为根节点右子树时,处理步骤相反。
若为双亲节点黑色,则设置插入根节点为黑色。
void rb_insert_color(struct rb_node *node, struct rb_root *root)
{
struct rb_node *parent, *gparent;
while ((parent = rb_parent(node)) && rb_is_red(parent))
{ //双亲不为空且颜色属性为黑色
gparent = rb_parent(parent); //祖父节点
if (parent == gparent->rb_left) //双亲节点为祖父左子树
{
{
register struct rb_node *uncle = gparent->rb_right; //叔父节点
if (uncle && rb_is_red(uncle))//叔父节点为红色
{
rb_set_black(uncle); //设置叔父为红色
rb_set_black(parent);//设置双亲为黑色
rb_set_red(gparent);//设置祖父为红色
node = gparent; //node赋为祖父节点
continue;
}
}
if (parent->rb_right == node) //node为双亲节点右子树
{
register struct rb_node *tmp;
__rb_rotate_left(parent, root);//parenth和根节点左旋转
tmp = parent; //交换parent和node指针指向
parent = node;
node = tmp;
}
rb_set_black(parent);
rb_set_red(gparent);
__rb_rotate_right(ggparent, root); //parent和root右旋转
} else { //双亲节点位于祖父节点左子树
{
register struct rb_node *uncle = gparent->rb_left;
if (uncle && rb_is_red(uncle)) //同上
{
rb_set_black(uncle);
rb_set_black(parent);
rb_set_red(gparent);
node = gparent;
continue;
}
}
if (parent->rb_left == node)
{
register struct rb_node *tmp;
__rb_rotate_right(parent, root);
tmp = parent;
parent = node;
node = tmp;
}
rb_set_black(parent);
rb_set_red(gparent);
__rb_rotate_left(gparent, root);
}
}
rb_set_black(root->rb_node);
}
3.删除
根据删除节点左右子树情况分为三种情况
void rb_erase(struct rb_node *node, struct rb_root *root)
{ //删除节点node
struct rb_node *child, *parent;
int color;
if (!node->rb_left) //删除节点无左子树
child = node->rb_right;
else if (!node->rb_right) //删除节点无右子树
child = node->rb_left;
else //左右子树都有
{
struct rb_node *old = node, *left;
node = node->rb_right;
while ((left = node->rb_left) != NULL)
node = left; //node的前驱替换
if (rb_parent(old)) {
if (rb_parent(old)->rb_left == old)
rb_parent(old)->rb_left = node;
else
rb_parent(old)->rb_right = node;
} else
root->rb_node = node;
child = node->rb_right;
parent = rb_parent(node);
color = rb_color(node);
if (parent == old) {
parent = node;
} else {
if (child)
rb_set_parent(child, parent);
parent->rb_left = child;
node->rb_right = old->rb_right;
rb_set_parent(old->rb_right, node);
}
node->rb_parent_color = old->rb_parent_color;
node->rb_left = old->rb_left;
rb_set_parent(old->rb_left, node);
goto color;
}
parent = rb_parent(node);
color = rb_color(node);
if (child)
rb_set_parent(child, parent);
if (parent)
{
if (parent->rb_left == node)
parent->rb_left = child;
else
parent->rb_right = child;
}
else
root->rb_node = child;
color:
if (color == RB_BLACK) //如果删除节点为黑色则调用__rb_erase_color
__rb_erase_color(child, parent, root);
}
4:遍历
struct rb_node *rb_first(struct rb_root *tree); //返回树的第一个节点
struct rb_node *rb_last(const struct rb_root *root) //返回树的最后一个节点/{
struct rb_node *n;
n = root->rb_node;
if (!n)
return NULL;
while (n->rb_right)
n = n->rb_right;
return n;
}
struct rb_node *rb_prev(const struct rb_node *node) //返回每个节点的前驱
{
struct rb_node *parent;
if (rb_parent(node) == node)
return NULL;
/* If we have a left-hand child, go down and then right as far
as we can. */
if (node->rb_left) {
node = node->rb_left;
while (node->rb_right)
node=node->rb_right;
return (struct rb_node *)node;
}
/* No left-hand children. Go up till we find an ancestor which
is a right-hand child of its parent */
while ((parent = rb_parent(node)) && node == parent->rb_left)
node = parent;
return parent;
}
struct rb_node *rb_next(const struct rb_node *node)//返回每个节点的后继
在应用程序中使用红黑树
#include "rbtree.h"
/* test.c */
#include <stdio.h>
#include <stdlib.h>
#include "rbtree.h"
struct mytype {
struct rb_node my_node;
int num;
};
struct mytype *my_search(struct rb_root *root, int num)
{
struct rb_node *node = root->rb_node;
while (node) {
struct mytype *data = container_of(node, struct mytype, my_node);
if (num < data->num)
node = node->rb_left;
else if (num > data->num)
node = node->rb_right;
else
return data;
}
return NULL;
}
int my_insert(struct rb_root *root, struct mytype *data)
{
struct rb_node **tmp = &(root->rb_node), *parent = NULL;
//查找插入位置
while (*tmp) {
struct mytype *poin = container_of(*tmp, struct mytype, my_node);
parent = *tmp;
if (data->num < poin->num)
tmp = &((*tmp)->rb_left);
else if (data->num > poin->num)
tmp = &((*tmp)->rb_right); /tmp为双亲
else
return -1;
}
rb_link_node(&data->my_node, parent, tmp); //添加新节点
rb_insert_color(&data->my_node, root); //平衡红黑树
return 0;
}
void my_delete(struct rb_root *root, int num)
{
struct mytype *data = my_search(root, num);
if (!data) {
fprintf(stderr, "Not found %d.\n", num);
return;
}
rb_erase(&data->my_node, root);
free(data);
}
void print_rbtree(struct rb_root *tree)
{
struct rb_node *node;
for (node = rb_first(tree); node; node = rb_next(node))
printf("%d ", rb_entry(node, struct mytype, my_node)->num);
printf("\n");
}
int main(int argc, char *argv[])
{
struct rb_root mytree = RB_ROOT;
int i, ret, num;
struct mytype *tmp;
if (argc < 2) {
fprintf(stderr, "Usage: %s num\n", argv[0]);
exit(-1);
}
num = atoi(argv[1]);
printf("Please enter %d integers:\n", num);
for (i = 0; i < num; i++) {
tmp = malloc(sizeof(struct mytype));
if (!tmp)
perror("Allocate dynamic memory");
scanf("%d", &tmp->num);
ret = my_insert(&mytree, tmp);
if (ret < 0) {
fprintf(stderr, "The %d already exists.\n", tmp->num);
free(tmp);
}
}
printf("\nthe first test\n");
print_rbtree(&mytree);
my_delete(&mytree, 21);
printf("\nthe second test\n");
print_rbtree(&mytree);
return 0;
}