Linux内核中红黑树的使用方法可以参考:linux/Documentation/rbtree.txt文件。本文的Linux内核以4.1.15版本为例。
红黑树是一种自平衡二叉搜索树,用于存储可排序的键/值数据对。 这与根树不同是用来有效地存储稀疏数组,从而使用长整数索引插入/访问/删除节点)和哈希表(它们没有被排序容易按顺序遍历,并且必须针对特定的大小和 哈希函数,rbtrees可以优雅地扩展存储任意键)。
红黑树中的数据节点是包含结构体rb_node成员的结构 :
struct mytype {
struct rb_node node;
char *keystring;
};
当处理指向内嵌结构体rb_node的指针时,包含的数据 结构可以通过标准的container_of()宏来访问。 此外, 单个成员可以通过rb_entry(node, type, member)直接访问。
在每个红黑树的根上都有一个rb_root结构,初始化为空:
struct rb_root mytree = RB_ROOT;1.2、在红黑树中搜索值
为红黑树编写搜索函数相当简单:从根处开始,比较每个值,必要时跟随左分支或右分支。
struct mytype *my_search(struct rb_root *root, char *string)
{
struct rb_node *node = root->rb_node;
while (node) {
struct mytype *data = container_of(node, struct mytype, node);
int result;
result = strcmp(string, data->keystring);
if (result < 0)
node = node->rb_left;
else if (result > 0)
node = node->rb_right;
else
return data;
}
return NULL;
}
1.3、在红黑树中插入数据
在红黑树中插入数据,首先需要搜索新节点要插入的位置,然后插入节点并重新平衡(“重新着色”)树。
插入的搜索与前面的搜索不同,它查找要在其上移植新节点的指针的位置。 新节点也是需要一个到其父节点的链接以实现重新平衡。
int my_insert(struct rb_root *root, struct mytype *data)
{
struct rb_node **new = &(root->rb_node), *parent = NULL;
while (*new) {
struct mytype *this = container_of(*new, struct mytype, node);
int result = strcmp(data->keystring, this->keystring);
parent = *new;
if (result < 0)
new = &((*new)->rb_left);
else if (result > 0)
new = &((*new)->rb_right);
else
return FALSE;
}
rb_link_node(&data->node, parent, new);
rb_insert_color(&data->node, root);
return TRUE;
}
1.4、在红黑树中删除数据
在红黑树中删除数据,需要调用函数:
void rb_erase(struct rb_node *victim, struct rb_root *tree);
例如:
struct mytype *data = mysearch(&mytree, "walrus");
if (data) {
rb_erase(&data->node, &mytree);
myfree(data);
}
二、使用实例
2.1、拷贝源文件
$ cp ../linux/lib/rbtree.c . $ cp ../linux/include/linux/rbtree.h2.2、修改源文件 2.2.1、修改rbtree.c文件
修改包含头文件的代码
//删除以下两行代码 #include#include //新增以下代码,即包含当前目录中的头文件rbtree.h #include "rbtree.h"
删除所有的EXPORT_SYMBOL宏
EXPORT_SYMBOL(rb_insert_color); EXPORT_SYMBOL(rb_erase); EXPORT_SYMBOL(rb_augment_insert); EXPORT_SYMBOL(rb_augment_erase_begin); EXPORT_SYMBOL(rb_augment_erase_end); EXPORT_SYMBOL(rb_first); EXPORT_SYMBOL(rb_last); EXPORT_SYMBOL(rb_next); EXPORT_SYMBOL(rb_prev); EXPORT_SYMBOL(rb_replace_node);2.2.2、修改rbtree.h文件
//删除以下两行代码 #include2.3、示例代码#include #undef NULL #if defined(__cplusplus) #define NULL 0 #else #define NULL ((void *)0) #endif #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #define container_of(ptr, type, member) ({ const typeof( ((type *)0)->member ) *__mptr = (ptr); (type *)( (char *)__mptr - offsetof(type,member) );})
#include2.4、编译并执行#include #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 *this = container_of(*tmp, struct mytype, my_node); parent = *tmp; if (data->num < this->num) tmp = &((*tmp)->rb_left); else if (data->num > this->num) tmp = &((*tmp)->rb_right); 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 numn", 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 testn"); print_rbtree(&mytree); my_delete(&mytree, 21); printf("nthe second testn"); print_rbtree(&mytree); return 0; }
$ gcc rbtree.c test.c -o test richard@tanglinux:~/algorithm/redblack$ ./test 10 Please enter 10 integers: 23 4 56 32 89 122 12 21 45 23 The 23 already exists. the first test 4 12 21 23 32 45 56 89 122 the second test 4 12 23 32 45 56 89 122



