中国Linux论坛首页 技术论坛| 文章荟萃| 藏经阁| 项目计划| 在线调查| 网站镜像| 软件仓库| 关于本站|

Linux 环境下的程序设计
   >> C/C++编程版
此话题阅读次数: 13126

打印
teawater版主
(Carpal Tunnel)
05-05-05 22:16
附加档案
[精华] [原创]红黑树 rbtree 实际使用例子一个  

这几天想作一个快速地址查询的东西 因为对查询的速度要求比较高
计划是弄一个HASH表再加一个AVL树 一提AVL树想起来Linux Kernel里有一个AVL的实现
决定抄一下 打开机器上存的2.4.24一看 发现AVL树已经被换成红黑树了 2.6也是
搜到了一个红黑树的介绍
target="_blank">http://www.frontfree.net/view/article_606.html
决定用红黑树 于是把Kernel里抠出来 主要是插入树和删除树的部分 自己写了别的部分
贴出来给各位兄弟看看有没啥错


rbtree.h
/*
Red Black Trees
(C) 1999 Andrea Arcangeli <andrea@suse.de>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

To use rbtrees you'll have to implement your own insert and search cores.
This will avoid us to use callbacks and to drop drammatically performances.
I know it's not the cleaner way, but in C (not in C++) to get
performances and genericity...

Some example of insert and search follows here. The search is a plain
normal search over an ordered tree. The insert instead must be implemented
int two steps: as first thing the code must insert the element in
order as a red leaf in the tree, then the support library function
rb_insert_color() must be called. Such function will do the
not trivial work to rebalance the rbtree if necessary.

-----------------------------------------------------------------------
static inline struct page * rb_search_page_cache(struct inode * inode,
unsigned long offset)
{
rb_node_t * n = inode->i_rb_page_cache.rb_node;
struct page * page;

while (n)
{
page = rb_entry(n, struct page, rb_page_cache);

if (offset < page->offset)
n = n->rb_left;
else if (offset > page->offset)
n = n->rb_right;
else
return page;
}
return NULL;
}

static inline struct page * __rb_insert_page_cache(struct inode * inode,
unsigned long offset,
rb_node_t * node)
{
rb_node_t ** p = &inode->i_rb_page_cache.rb_node;
rb_node_t * parent = NULL;
struct page * page;

while (*p)
{
parent = *p;
page = rb_entry(parent, struct page, rb_page_cache);

if (offset < page->offset)
p = &(*p)->rb_left;
else if (offset > page->offset)
p = &(*p)->rb_right;
else
return page;
}

rb_link_node(node, parent, p);

return NULL;
}

static inline struct page * rb_insert_page_cache(struct inode * inode,
unsigned long offset,
rb_node_t * node)
{
struct page * ret;
if ((ret = __rb_insert_page_cache(inode, offset, node)))
goto out;
rb_insert_color(node, &inode->i_rb_page_cache);
out:
return ret;
}
-----------------------------------------------------------------------
teawater:This file is come from the Linux Kernel.
*/

#ifndef _LINUX_RBTREE_H
#define _LINUX_RBTREE_H

typedef struct rb_node_s {
struct rb_node_s * rb_parent;
int rb_color;
#define RB_RED 0
#define RB_BLACK 1
struct rb_node_s * rb_right;
struct rb_node_s * rb_left;
}rb_node_t;

typedef struct rb_root_s {
struct rb_node_s * rb_node;
}rb_root_t;

#define RB_ROOT (rb_root_t){ NULL, }
#define rb_entry(ptr, type, member) ((type *)((char *)(ptr)-(unsigned
long)(&((type *)0)->member)))


static inline void
rb_link_node(rb_node_t * node, rb_node_t * parent, rb_node_t ** rb_link)
{
node->rb_parent = parent;
node->rb_color = RB_RED;
node->rb_left = node->rb_right = NULL;

*rb_link = node;
}

static void
__rb_rotate_left(rb_node_t * node, rb_root_t * root)
{
rb_node_t * right = node->rb_right;

if ((node->rb_right = right->rb_left))
right->rb_left->rb_parent = node;
right->rb_left = node;

if ((right->rb_parent = node->rb_parent))
{
if (node == node->rb_parent->rb_left)
node->rb_parent->rb_left = right;
else
node->rb_parent->rb_right = right;
}
else
root->rb_node = right;
node->rb_parent = right;
}

static void
__rb_rotate_right(rb_node_t * node, rb_root_t * root)
{
rb_node_t * left = node->rb_left;

if ((node->rb_left = left->rb_right))
left->rb_right->rb_parent = node;
left->rb_right = node;

if ((left->rb_parent = node->rb_parent))
{
if (node == node->rb_parent->rb_right)
node->rb_parent->rb_right = left;
else
node->rb_parent->rb_left = left;
}
else
root->rb_node = left;
node->rb_parent = left;
}

static void
rb_insert_color(rb_node_t * node, rb_root_t * root)
{
rb_node_t * parent, * gparent;

while ((parent = node->rb_parent) && parent->rb_color == RB_RED)
{
gparent = parent->rb_parent;

if (parent == gparent->rb_left)
{
{
register rb_node_t * uncle = gparent->rb_right;
if (uncle && uncle->rb_color == RB_RED)
{
uncle->rb_color = RB_BLACK;
parent->rb_color = RB_BLACK;
gparent->rb_color = RB_RED;
node = gparent;
continue;
}
}

if (parent->rb_right == node)
{
register rb_node_t * tmp;
__rb_rotate_left(parent, root);
tmp = parent;
parent = node;
node = tmp;
}

parent->rb_color = RB_BLACK;
gparent->rb_color = RB_RED;
__rb_rotate_right(gparent, root);
} else {
{
register rb_node_t * uncle = gparent->rb_left;
if (uncle && uncle->rb_color == RB_RED)
{
uncle->rb_color = RB_BLACK;
parent->rb_color = RB_BLACK;
gparent->rb_color = RB_RED;
node = gparent;
continue;
}
}

if (parent->rb_left == node)
{
register rb_node_t * tmp;
__rb_rotate_right(parent, root);
tmp = parent;
parent = node;
node = tmp;
}

parent->rb_color = RB_BLACK;
gparent->rb_color = RB_RED;
__rb_rotate_left(gparent, root);
}
}

root->rb_node->rb_color = RB_BLACK;
}

static void
__rb_erase_color(rb_node_t * node, rb_node_t * parent, rb_root_t * root)
{
rb_node_t * other;

while ((!node || node->rb_color == RB_BLACK) && node != root->rb_node)
{
if (parent->rb_left == node)
{
other = parent->rb_right;
if (other->rb_color == RB_RED)
{
other->rb_color = RB_BLACK;
parent->rb_color = RB_RED;
__rb_rotate_left(parent, root);
other = parent->rb_right;
}
if ((!other->rb_left ||
other->rb_left->rb_color == RB_BLACK)
&& (!other->rb_right ||
other->rb_right->rb_color == RB_BLACK))
{
other->rb_color = RB_RED;
node = parent;
parent = node->rb_parent;
}
else
{
if (!other->rb_right ||
other->rb_right->rb_color == RB_BLACK)
{
register rb_node_t * o_left;
if ((o_left = other->rb_left))
o_left->rb_color = RB_BLACK;
other->rb_color = RB_RED;
__rb_rotate_right(other, root);
other = parent->rb_right;
}
other->rb_color = parent->rb_color;
parent->rb_color = RB_BLACK;
if (other->rb_right)
other->rb_right->rb_color = RB_BLACK;
__rb_rotate_left(parent, root);
node = root->rb_node;
break;
}
}
else
{
other = parent->rb_left;
if (other->rb_color == RB_RED)
{
other->rb_color = RB_BLACK;
parent->rb_color = RB_RED;
__rb_rotate_right(parent, root);
other = parent->rb_left;
}
if ((!other->rb_left ||
other->rb_left->rb_color == RB_BLACK)
&& (!other->rb_right ||
other->rb_right->rb_color == RB_BLACK))
{
other->rb_color = RB_RED;
node = parent;
parent = node->rb_parent;
}
else
{
if (!other->rb_left ||
other->rb_left->rb_color == RB_BLACK)
{
register rb_node_t * o_right;
if ((o_right = other->rb_right))
o_right->rb_color = RB_BLACK;
other->rb_color = RB_RED;
__rb_rotate_left(other, root);
other = parent->rb_left;
}
other->rb_color = parent->rb_color;
parent->rb_color = RB_BLACK;
if (other->rb_left)
other->rb_left->rb_color = RB_BLACK;
__rb_rotate_right(parent, root);
node = root->rb_node;
break;
}
}
}
if (node)
node->rb_color = RB_BLACK;
}

static void
rb_erase(rb_node_t * node, rb_root_t * root)
{
rb_node_t * child, * parent;
int color;

if (!node->rb_left)
child = node->rb_right;
else if (!node->rb_right)
child = node->rb_left;
else
{
rb_node_t * old = node, * left;

node = node->rb_right;
while ((left = node->rb_left))
node = left;
child = node->rb_right;
parent = node->rb_parent;
color = node->rb_color;

if (child)
child->rb_parent = parent;
if (parent)
{
if (parent->rb_left == node)
parent->rb_left = child;
else
parent->rb_right = child;
}
else
root->rb_node = child;

if (node->rb_parent == old)
parent = node;
node->rb_parent = old->rb_parent;
node->rb_color = old->rb_color;
node->rb_right = old->rb_right;
node->rb_left = old->rb_left;

if (old->rb_parent)
{
if (old->rb_parent->rb_left == old)
old->rb_parent->rb_left = node;
else
old->rb_parent->rb_right = node;
} else
root->rb_node = node;

old->rb_left->rb_parent = node;
if (old->rb_right)
old->rb_right->rb_parent = node;
goto color;
}

parent = node->rb_parent;
color = node->rb_color;

if (child)
child->rb_parent = 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(child, parent, root);
}

#endif /* _LINUX_RBTREE_H */

test.c
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include "rbtree.h"

typedef unsigned int CORE_ADDR;
typedef struct rb_addr_s {
rb_node_t rb_node;
CORE_ADDR addr;
}rb_addr_t;

static inline rb_addr_t *
rb_find_addr_struct(CORE_ADDR addr, rb_root_t *root, rb_node_t **ret_parent, rb_node_t
***ret_link)
{
rb_node_t **link = &root->rb_node;
rb_node_t *parent = NULL;
rb_addr_t *rb_addr = NULL;
rb_addr_t *ret_rb_addr = NULL;

while (*link) {
parent = *link;
rb_addr = rb_entry(parent, rb_addr_t, rb_node);

if (addr < rb_addr->addr) {
link = &(*link)->rb_left;
}
else if (addr > rb_addr->addr) {
link = &(*link)->rb_right;
}
else {
ret_rb_addr = rb_addr;
break;
}
}
if (ret_parent) {
*ret_parent = parent;
}
if (ret_link) {
*ret_link = link;
}

return(ret_rb_addr);
}

int
rb_insert_addr(CORE_ADDR addr, rb_root_t *root)
{
rb_node_t **rb_link;
rb_node_t *rb_parent;
rb_addr_t *rb_addr = NULL;

if (rb_find_addr_struct(addr, root, &rb_parent, &rb_link)) {
return(-1);
}
rb_addr = (rb_addr_t *)malloc(sizeof(rb_addr_t));
if (!rb_addr) {
return(-1);
}
rb_addr->addr = addr;
rb_link_node(&rb_addr->rb_node, rb_parent, rb_link);
rb_insert_color(&rb_addr->rb_node, root);

return(0);
}

int
rb_remove_addr(CORE_ADDR addr, rb_root_t *root)
{
rb_addr_t *rb_addr = rb_find_addr_struct(addr, root, NULL, NULL);

if (!rb_addr) {
return(-1);
}
rb_erase(&rb_addr->rb_node, root);
free(rb_addr);

return(0);
}

static inline int
rb_find_addr(CORE_ADDR addr, rb_root_t *root)
{
rb_node_t **link = &root->rb_node;
rb_node_t *parent = NULL;
rb_addr_t *rb_addr;

while (*link) {
parent = *link;
rb_addr = rb_entry(parent, rb_addr_t, rb_node);

if (addr < rb_addr->addr) {
link = &(*link)->rb_left;
}
else if (addr > rb_addr->addr) {
link = &(*link)->rb_right;
}
else {
return(1);
}
}

return(0);
}

int
main(int argc,char *argv[], char *envp[])
{
rb_root_t addr_root;

addr_root = RB_ROOT;

//right insert
printf("right insert\n");
if (rb_insert_addr(0x1, &addr_root)) {
printf("rb_insert_addr error\n");
}
if (rb_insert_addr(0xc0028018, &addr_root)) {
printf("rb_insert_addr error\n");
}
if (rb_insert_addr(0xd014cb68, &addr_root)) {
printf("rb_insert_addr error\n");
}
if (rb_insert_addr(0x74697277, &addr_root)) {
printf("rb_insert_addr error\n");
}
if (rb_insert_addr(0xc00959f8, &addr_root)) {
printf("rb_insert_addr error\n");
}
if (rb_insert_addr(0x959f8, &addr_root)) {
printf("rb_insert_addr error\n");
}
if (rb_insert_addr(0xe3740ffa, &addr_root)) {
printf("rb_insert_addr error\n");
}
if (rb_insert_addr(0x31321, &addr_root)) {
printf("rb_insert_addr error\n");
}
if (rb_insert_addr(0x765702, &addr_root)) {
printf("rb_insert_addr error\n");
}
if (rb_insert_addr(0xf123, &addr_root)) {
printf("rb_insert_addr error\n");
}

//wrong insert
printf("wrong insert\n");
if (rb_insert_addr(0x1, &addr_root)) {
printf("rb_insert_addr error\n");
}
if (rb_insert_addr(0xc0028018, &addr_root)) {
printf("rb_insert_addr error\n");
}
if (rb_insert_addr(0xd014cb68, &addr_root)) {
printf("rb_insert_addr error\n");
}
if (rb_insert_addr(0x74697277, &addr_root)) {
printf("rb_insert_addr error\n");
}
if (rb_insert_addr(0xc00959f8, &addr_root)) {
printf("rb_insert_addr error\n");
}
if (rb_insert_addr(0x959f8, &addr_root)) {
printf("rb_insert_addr error\n");
}
if (rb_insert_addr(0xe3740ffa, &addr_root)) {
printf("rb_insert_addr error\n");
}
if (rb_insert_addr(0x31321, &addr_root)) {
printf("rb_insert_addr error\n");
}
if (rb_insert_addr(0x765702, &addr_root)) {
printf("rb_insert_addr error\n");
}
if (rb_insert_addr(0xf123, &addr_root)) {
printf("rb_insert_addr error\n");
}

//right find
printf("right find\n");
if (rb_find_addr(0x1, &addr_root)) {
printf("rb_find_addr ok\n");
}
if (rb_find_addr(0xc0028018, &addr_root)) {
printf("rb_find_addr ok\n");
}
if (rb_find_addr(0xd014cb68, &addr_root)) {
printf("rb_find_addr ok\n");
}
if (rb_find_addr(0x74697277, &addr_root)) {
printf("rb_find_addr ok\n");
}
if (rb_find_addr(0xc00959f8, &addr_root)) {
printf("rb_find_addr ok\n");
}
if (rb_find_addr(0x959f8, &addr_root)) {
printf("rb_find_addr ok\n");
}
if (rb_find_addr(0xe3740ffa, &addr_root)) {
printf("rb_find_addr ok\n");
}
if (rb_find_addr(0x31321, &addr_root)) {
printf("rb_find_addr ok\n");
}
if (rb_find_addr(0x765702, &addr_root)) {
printf("rb_find_addr ok\n");
}
if (rb_find_addr(0xf123, &addr_root)) {
printf("rb_find_addr ok\n");
}

//wrong find
printf("wrong find\n");
if (rb_find_addr(0x0, &addr_root)) {
printf("rb_find_addr error\n");
}
if (rb_find_addr(0xc002801, &addr_root)) {
printf("rb_find_addr error\n");
}
if (rb_find_addr(0xd014cb6, &addr_root)) {
printf("rb_find_addr error\n");
}
if (rb_find_addr(0x7469727, &addr_root)) {
printf("rb_find_addr error\n");
}
if (rb_find_addr(0xc00959f, &addr_root)) {
printf("rb_find_addr error\n");
}
if (rb_find_addr(0x959f, &addr_root)) {
printf("rb_find_addr error\n");
}
if (rb_find_addr(0xe3740ff, &addr_root)) {
printf("rb_find_addr error\n");
}
if (rb_find_addr(0x3132, &addr_root)) {
printf("rb_find_addr error\n");
}
if (rb_find_addr(0x76570, &addr_root)) {
printf("rb_find_addr error\n");
}
if (rb_find_addr(0xf12, &addr_root)) {
printf("rb_find_addr error\n");
}

//right remove
printf("right remove\n");
if (rb_remove_addr(0x1, &addr_root)) {
printf("rb_remove_addr error\n");
}
if (rb_remove_addr(0xc0028018, &addr_root)) {
printf("rb_remove_addr error\n");
}
if (rb_remove_addr(0xd014cb68, &addr_root)) {
printf("rb_remove_addr error\n");
}
if (rb_remove_addr(0x74697277, &addr_root)) {
printf("rb_remove_addr error\n");
}
if (rb_remove_addr(0xc00959f8, &addr_root)) {
printf("rb_remove_addr error\n");
}
if (rb_remove_addr(0x959f8, &addr_root)) {
printf("rb_remove_addr error\n");
}
if (rb_remove_addr(0xe3740ffa, &addr_root)) {
printf("rb_remove_addr error\n");
}
if (rb_remove_addr(0x31321, &addr_root)) {
printf("rb_remove_addr error\n");
}
if (rb_remove_addr(0x765702, &addr_root)) {
printf("rb_remove_addr error\n");
}
if (rb_remove_addr(0xf123, &addr_root)) {
printf("rb_remove_addr error\n");
}

//wrong remove
printf("wrong remove\n");
if (rb_remove_addr(0x1, &addr_root)) {
printf("rb_remove_addr error\n");
}
if (rb_remove_addr(0xc0028018, &addr_root)) {
printf("rb_remove_addr error\n");
}
if (rb_remove_addr(0xd014cb68, &addr_root)) {
printf("rb_remove_addr error\n");
}
if (rb_remove_addr(0x74697277, &addr_root)) {
printf("rb_remove_addr error\n");
}
if (rb_remove_addr(0xc00959f8, &addr_root)) {
printf("rb_remove_addr error\n");
}
if (rb_remove_addr(0x959f8, &addr_root)) {
printf("rb_remove_addr error\n");
}
if (rb_remove_addr(0xe3740ffa, &addr_root)) {
printf("rb_remove_addr error\n");
}
if (rb_remove_addr(0x31321, &addr_root)) {
printf("rb_remove_addr error\n");
}
if (rb_remove_addr(0x765702, &addr_root)) {
printf("rb_remove_addr error\n");
}
if (rb_remove_addr(0xf123, &addr_root)) {
printf("rb_remove_addr error\n");
}

return(0);
}




--------------------
读了这么多年的书 还是觉得幼儿园好混

文章选项: 打印


整个主题
文章标题张贴者:张贴日期
*[精华] [原创]红黑树 rbtree 实际使用例子一个 teawater版主   05-05-05 22:16
.*[精华] Re: [原创]红黑树 rbtree 实际使用例子一个 bbwolf   05-05-06 17:49
.*[精华] Re: [原创]红黑树 rbtree 实际使用例子一个 teawater版主   05-05-06 18:07
.*[精华] Re: [原创]红黑树 rbtree 实际使用例子一个 bbwolf   05-05-06 19:52
.*[精华] Re: [原创]红黑树 rbtree 实际使用例子一个 albcamus   05-05-08 11:54
前往讨论区

Contact Us LINUXFORUM.NET