Linux内核的红黑树RB_TREE和FreeBSD 8.0里面的AVL_TREE比较之一 RB_TREE
这里不涉及到avl树和红黑树谁优谁劣,只是谈谈在两种实现的一些细节,以及最后给出一些性能比较。
这里先给出Linux下面的红黑树的实现,因为Linux下面的两个宏定义不好直接使用,原型如下:
- #define rb_entry(ptr, type, member) container_of(ptr, type, member)
- #ifndef container_of
- /**
- * container_of – cast a member of a structure out to the containing structure
- * @ptr: the pointer to the member.
- * @type: the type of the container struct this is embedded in.
- * @member: the name of the member within the struct.
- *
- */
- #define container_of(ptr, type, member) ({ \
- const typeof(((type *)0)->member) * __mptr = (ptr); \
- (type *)((char *)__mptr – offsetof(type, member)); })
- #endif
- #ifndef offsetof
- #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
- #endif
修改如下:
- #ifndef offsetof
- #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
- #endif
- #ifndef container_of
- /**
- * container_of – cast a member of a structure out to the containing structure
- * @ptr: the pointer to the member.
- * @type: the type of the container struct this is embedded in.
- * @member: the name of the member within the struct.
- *
- * !!! modify the typeof marco, just use the rb_node
- */
- #define container_of(ptr, type, member) \
- (((char *)ptr) – offsetof(type, member))
- #endif
- #define rb_entry(ptr, type, member) container_of(ptr, type, member)
语义可以认为不变的。
linux的RB_TREE源代码移植到vc上后,命名为:rb_tree.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
- linux/include/linux/rbtree.h
- 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
- in two steps: First, the code must insert the element in order as a red leaf
- in the tree, and 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)
- {
- struct rb_node * 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,
- struct rb_node * node)
- {
- struct rb_node ** p = &inode->i_rb_page_cache.rb_node;
- struct rb_node * 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,
- struct rb_node * 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;
- }
- ———————————————————————–
- */
- #ifndef _LINUX_RBTREE_H
- #define _LINUX_RBTREE_H
- #define EXPORT_SYMBOL(i)
- #pragma pack (push)
- #pragma pack(4)
- 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;
- } ;
- #pragma pack (pop)
- /* The alignment might seem pointless, but allegedly CRIS needs it */
- struct rb_root
- {
- struct rb_node *rb_node;
- int (*cmp)(void *src, void *dst);
- void (*insert)(struct rb_root *root, void *ins);
- void (*remove)(struct rb_root *root, void *del);
- };
- #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;
- }
- static inline void rb_set_color(struct rb_node *rb, int color)
- {
- rb->rb_parent_color = (rb->rb_parent_color & ~1) | color;
- }
- #ifndef offsetof
- #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
- #endif
- #ifndef container_of
- /**
- * container_of – cast a member of a structure out to the containing structure
- * @ptr: the pointer to the member.
- * @type: the type of the container struct this is embedded in.
- * @member: the name of the member within the struct.
- *
- * !!! modify the typeof marco, just use the rb_node
- */
- #define container_of(ptr, type, member) \
- (((char *)ptr) – offsetof(type, member))
- #endif
- #define RB_ROOT (struct rb_root) { NULL, }
- #define rb_entry(ptr, type, member) container_of(ptr, type, member)
- #define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL)
- #define RB_EMPTY_NODE(node) (rb_parent(node) == node)
- #define RB_CLEAR_NODE(node) (rb_set_parent(node, node))
- static inline void rb_init_node(struct rb_node *rb)
- {
- rb->rb_parent_color = 0;
- rb->rb_right = NULL;
- rb->rb_left = NULL;
- RB_CLEAR_NODE(rb);
- }
- extern void rb_insert_color(struct rb_node *, struct rb_root *);
- extern void rb_erase(struct rb_node *, struct rb_root *);
- typedef void (*rb_augment_f)(struct rb_node *node, void *data);
- extern void rb_augment_insert(struct rb_node *node,
- rb_augment_f func, void *data);
- extern struct rb_node *rb_augment_erase_begin(struct rb_node *node);
- extern void rb_augment_erase_end(struct rb_node *node,
- rb_augment_f func, void *data);
- /* Find logical next and previous nodes in a tree */
- extern struct rb_node *rb_next(const struct rb_node *);
- extern struct rb_node *rb_prev(const struct rb_node *);
- extern struct rb_node *rb_first(const struct rb_root *);
- extern struct rb_node *rb_last(const struct rb_root *);
- /* Fast replacement of a single node without remove/rebalance/add/rebalance */
- extern void rb_replace_node(struct rb_node *victim, struct rb_node *new_node_node,
- struct rb_root *root);
- 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;
- }
- #endif /* _LINUX_RBTREE_H */
实现文件移植之后,命名为rb_tree.cpp, 如下:
- /*
- Red Black Trees
- (C) 1999 Andrea Arcangeli <andrea@SUSE.de>
- (C) 2002 David Woodhouse <dwmw2@infradead.org>
- 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
- linux/lib/rbtree.c
- */
- #include “rb_tree.h”
- static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
- {
- struct rb_node *right = node->rb_right;
- struct rb_node *parent = rb_parent(node);
- if ((node->rb_right = right->rb_left))
- rb_set_parent(right->rb_left, node);
- right->rb_left = node;
- rb_set_parent(right, parent);
- if (parent)
- {
- if (node == parent->rb_left)
- parent->rb_left = right;
- else
- parent->rb_right = right;
- }
- else
- root->rb_node = right;
- rb_set_parent(node, right);
- }
- static void __rb_rotate_right(struct rb_node *node, struct rb_root *root)
- {
- struct rb_node *left = node->rb_left;
- struct rb_node *parent = rb_parent(node);
- if ((node->rb_left = left->rb_right))
- rb_set_parent(left->rb_right, node);
- left->rb_right = node;
- rb_set_parent(left, parent);
- if (parent)
- {
- if (node == parent->rb_right)
- parent->rb_right = left;
- else
- parent->rb_left = left;
- }
- else
- root->rb_node = left;
- rb_set_parent(node, left);
- }
- 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;
- continue;
- }
- }
- if (parent->rb_right == node)
- {
- register struct rb_node *tmp;
- __rb_rotate_left(parent, root);
- tmp = parent;
- parent = node;
- node = tmp;
- }
- rb_set_black(parent);
- rb_set_red(gparent);
- __rb_rotate_right(gparent, 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);
- }
- EXPORT_SYMBOL(rb_insert_color);
- static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
- struct rb_root *root)
- {
- struct rb_node *other;
- while ((!node || rb_is_black(node)) && node != root->rb_node)
- {
- if (parent->rb_left == node)
- {
- other = parent->rb_right;
- if (rb_is_red(other))
- {
- rb_set_black(other);
- rb_set_red(parent);
- __rb_rotate_left(parent, root);
- other = parent->rb_right;
- }
- if ((!other->rb_left || rb_is_black(other->rb_left)) &&
- (!other->rb_right || rb_is_black(other->rb_right)))
- {
- rb_set_red(other);
- node = parent;
- parent = rb_parent(node);
- }
- else
- {
- if (!other->rb_right || rb_is_black(other->rb_right))
- {
- rb_set_black(other->rb_left);
- rb_set_red(other);
- __rb_rotate_right(other, root);
- other = parent->rb_right;
- }
- rb_set_color(other, rb_color(parent));
- rb_set_black(parent);
- rb_set_black(other->rb_right);
- __rb_rotate_left(parent, root);
- node = root->rb_node;
- break;
- }
- }
- else
- {
- other = parent->rb_left;
- if (rb_is_red(other))
- {
- rb_set_black(other);
- rb_set_red(parent);
- __rb_rotate_right(parent, root);
- other = parent->rb_left;
- }
- if ((!other->rb_left || rb_is_black(other->rb_left)) &&
- (!other->rb_right || rb_is_black(other->rb_right)))
- {
- rb_set_red(other);
- node = parent;
- parent = rb_parent(node);
- }
- else
- {
- if (!other->rb_left || rb_is_black(other->rb_left))
- {
- rb_set_black(other->rb_right);
- rb_set_red(other);
- __rb_rotate_left(other, root);
- other = parent->rb_left;
- }
- rb_set_color(other, rb_color(parent));
- rb_set_black(parent);
- rb_set_black(other->rb_left);
- __rb_rotate_right(parent, root);
- node = root->rb_node;
- break;
- }
- }
- }
- if (node)
- rb_set_black(node);
- }
- void rb_erase(struct rb_node *node, struct rb_root *root)
- {
- 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;
- 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(child, parent, root);
- }
- EXPORT_SYMBOL(rb_erase);
- static void rb_augment_path(struct rb_node *node, rb_augment_f func, void *data)
- {
- struct rb_node *parent;
- up:
- func(node, data);
- parent = rb_parent(node);
- if (!parent)
- return;
- if (node == parent->rb_left && parent->rb_right)
- func(parent->rb_right, data);
- else if (parent->rb_left)
- func(parent->rb_left, data);
- node = parent;
- goto up;
- }
- /*
- * after inserting @node into the tree, update the tree to account for
- * both the new_node entry and any damage done by rebalance
- */
- void rb_augment_insert(struct rb_node *node, rb_augment_f func, void *data)
- {
- if (node->rb_left)
- node = node->rb_left;
- else if (node->rb_right)
- node = node->rb_right;
- rb_augment_path(node, func, data);
- }
- EXPORT_SYMBOL(rb_augment_insert);
- /*
- * before removing the node, find the deepest node on the rebalance path
- * that will still be there after @node gets removed
- */
- struct rb_node *rb_augment_erase_begin(struct rb_node *node)
- {
- struct rb_node *deepest;
- if (!node->rb_right && !node->rb_left)
- deepest = rb_parent(node);
- else if (!node->rb_right)
- deepest = node->rb_left;
- else if (!node->rb_left)
- deepest = node->rb_right;
- else {
- deepest = rb_next(node);
- if (deepest->rb_right)
- deepest = deepest->rb_right;
- else if (rb_parent(deepest) != node)
- deepest = rb_parent(deepest);
- }
- return deepest;
- }
- EXPORT_SYMBOL(rb_augment_erase_begin);
- /*
- * after removal, update the tree to account for the removed entry
- * and any rebalance damage.
- */
- void rb_augment_erase_end(struct rb_node *node, rb_augment_f func, void *data)
- {
- if (node)
- rb_augment_path(node, func, data);
- }
- EXPORT_SYMBOL(rb_augment_erase_end);
- /*
- * This function returns the first node (in sort order) of the tree.
- */
- struct rb_node *rb_first(const struct rb_root *root)
- {
- struct rb_node *n;
- n = root->rb_node;
- if (!n)
- return NULL;
- while (n->rb_left)
- n = n->rb_left;
- return n;
- }
- EXPORT_SYMBOL(rb_first);
- 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;
- }
- EXPORT_SYMBOL(rb_last);
- struct rb_node *rb_next(const struct rb_node *node)
- {
- struct rb_node *parent;
- if (rb_parent(node) == node)
- return NULL;
- /* If we have a right-hand child, go down and then left as far
- as we can. */
- if (node->rb_right) {
- node = node->rb_right;
- while (node->rb_left)
- node=node->rb_left;
- return (struct rb_node *)node;
- }
- /* No right-hand children. Everything down and left is
- smaller than us, so any ‘next’ node must be in the general
- direction of our parent. Go up the tree; any time the
- ancestor is a right-hand child of its parent, keep going
- up. First time it’s a left-hand child of its parent, said
- parent is our ‘next’ node. */
- while ((parent = rb_parent(node)) && node == parent->rb_right)
- node = parent;
- return parent;
- }
- EXPORT_SYMBOL(rb_next);
- 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;
- }
- EXPORT_SYMBOL(rb_prev);
- void rb_replace_node(struct rb_node *victim, struct rb_node *new_node,
- struct rb_root *root)
- {
- struct rb_node *parent = rb_parent(victim);
- /* Set the surrounding nodes to point to the replacement */
- if (parent) {
- if (victim == parent->rb_left)
- parent->rb_left = new_node;
- else
- parent->rb_right = new_node;
- } else {
- root->rb_node = new_node;
- }
- if (victim->rb_left)
- rb_set_parent(victim->rb_left, new_node);
- if (victim->rb_right)
- rb_set_parent(victim->rb_right, new_node);
- /* Copy the pointers/colour from the victim to the replacement */
- *new_node = *victim;
- }
- EXPORT_SYMBOL(rb_replace_node);
其实,可以看出,linux内核里面并没有提供直接可以用的insert delete 以及walk遍历的函数接口,linux提供的是最基本一个插入节点后的re-fixup, 删除后的re-fixup,以及walk需要的get-firt, get-next等等。
这里是需要自己提供插入,删除,以及walk函数的,相比freebsd的avl树,完全就是一步到位了,而且好用很多,这里不谈谁好用,然后举例简单说说怎么使用linux的基本的这些函数,晚点会比较二者在插入删除以及walk方面的优劣。
自己提供相应的一些接口了,时间有限随便写写:
应用头文件,rb_tree_main.h:
- #ifndef RB_TREE_MAIN_H
- #define RB_TREE_MAIN_H
- #include “rb_tree.h”
- void my_insert(struct rb_root *root, void *ins);
- int my_cmp(void *src, void *dest);
- void my_rb_walk(const struct rb_root *root);
- void my_remove(struct rb_root *g_my_root, void *del);
- #endif
man文件:rb_tree_main.cpp
- // rb_tree_main.cpp : Defines the entry point for the console application.
- //
- #include <string.h>
- #include <stdlib.h>
- #include “rb_tree.h”
- #include “rb_tree_main.h”
- typedef struct my_rb
- {
- int rand_val;
- struct rb_node my_rb_node;
- }my_rb;
- struct rb_root g_my_root = {NULL, my_cmp, my_insert, my_remove};
- void my_insert(struct rb_root *root, void *ins)
- {
- struct my_rb *iter;
- struct my_rb *src = (struct my_rb *)ins;
- struct rb_node **p = &root->rb_node;
- struct rb_node *parent = NULL;
- if(!ins)
- {
- return;
- }
- while (*p != NULL) {
- parent = *p;
- iter = (struct my_rb *)rb_entry(parent, struct my_rb, my_rb_node);
- if (root->cmp(src, iter) < 0)
- p = &(*p)->rb_left;
- else
- p = &(*p)->rb_right;
- }
- rb_link_node(&src->my_rb_node, parent, p);
- rb_insert_color(&src->my_rb_node, root);
- }
- int my_cmp(void *src, void *dest)
- {
- struct my_rb *my_src = (struct my_rb *)src;
- struct my_rb *my_dest = (struct my_rb *)dest;
- if(!my_src || !my_dest)
- {
- return 0;
- }
- if(my_src->rand_val < my_dest->rand_val)
- {
- return -1;
- }
- else if(my_src->rand_val > my_dest->rand_val)
- {
- return 1;
- }
- else
- {
- return 0;
- }
- }
- void my_remove(struct rb_root *g_my_root, void *del)
- {
- struct my_rb *entry = NULL;
- struct my_rb *del_node = (struct my_rb *)del;
- struct rb_node *n = NULL;
- if(!g_my_root || !del)
- {
- return;
- }
- n = g_my_root->rb_node;
- while (n)
- {
- entry = (struct my_rb *)rb_entry(n, struct my_rb, my_rb_node);
- if (g_my_root->cmp(entry, del_node) > 0)
- {
- n = n->rb_left;
- }
- else if (g_my_root->cmp(entry, del_node) < 0)
- {
- n = n->rb_right;
- }
- else
- {
- rb_erase(n, g_my_root);
- free(entry);
- entry = NULL;
- return ;
- }
- }
- return ;
- }
- void my_rb_walk(const struct rb_root *root)
- {
- struct rb_node *temp = rb_first(root);
- struct my_rb *my_entry = NULL;
- while(temp)
- {
- my_entry = (struct my_rb *)rb_entry(temp, my_rb, my_rb_node);
- printf(“node with rand_val %d .\n”, my_entry->rand_val);
- temp = rb_next(temp);
- }
- }
- int main(int argc, char* argv[])
- {
- struct my_rb *my_rb_node = NULL;
- struct my_rb del_node = {4, {0}};
- for (int i = 0; i < 5; i++)
- {
- my_rb_node = (struct my_rb *)malloc(sizeof *my_rb_node);
- memset(my_rb_node, 0, sizeof *my_rb_node);
- my_rb_node->rand_val = i;
- g_my_root.insert(&g_my_root, my_rb_node);
- }
- my_rb_walk(&g_my_root);
- g_my_root.remove(&g_my_root, &del_node);
- my_rb_walk(&g_my_root);
- return 0;
- }
注意四点:
1、insert里面的双重指针,直接找到要插入的位置的父节点,省去了一堆赋值比如parent->left or right = p, p->parent 啥啥啥的,直接在父节点(叶子节点)的左或者右节点NULL的取一次地址,然后,地址上面写值,不细说了;
2、插入的节点应该动态分配,或者是已经静态分配好的多个节点
3、删除操作,内核提供的只是re-fixup,不会帮你释放内存的,我们要做的是找到这个节点,然后调用内核提供的rb_erase,把节点从rb树上移去,如果是动态分配,再释放之。
4、内核的红黑树是带有parent属性的,只是么有用指针,而是把parent和left和right子标记用了一个字段而已:
- unsigned long rb_parent_color;
最低的一位用作了left和right的flag,最高的31位,用作存储parent指针的地址,这种rb树就要求插入的节点地址必须是偶数的,一般的cpu架构使得分配出来的内存都是偶数地址对齐的了,但是有些也会以奇数开始,比如ppc,就可能动态分配出一个节点就是从奇数地址开始的。只要是偶数地址开始那么地址的最低位一定是0了。
其实在3.0.1的内核里面是这种rb设计,在早期的内核里面rb_node就是另外一种设计了,是引入了parent指针的,比如2.6.11的内核的结构体设计如下:
- struct rb_node
- {
- struct rb_node *rb_parent;
- int rb_color;
- #define RB_RED 0
- #define RB_BLACK 1
- struct rb_node *rb_right;
- struct rb_node *rb_left;
- };
其实在freebsd 8.0的avl树64位设计就是这种,32二位的设计类似于早些时候的内核的rb树的节点设计:
- #ifndef _LP64
- struct avl_node {
- struct avl_node *avl_child[2]; /* left/right children */
- struct avl_node *avl_parent; /* this node’s parent */
- unsigned short avl_child_index; /* my index in parent’s avl_child[] */
- short avl_balance; /* balance value: -1, 0, +1 */
- };
- #else /* _LP64 */
- /*
- * for 64 bit machines, avl_pcb contains parent pointer, balance and child_index
- * values packed in the following manner:
- *
- * |63 3| 2 |1 0 |
- * |————————————-|—————–|————-|
- * | avl_parent hi order bits | avl_child_index | avl_balance |
- * | | | + 1 |
- * |————————————-|—————–|————-|
- *
- */
- struct avl_node {
- struct avl_node *avl_child[2]; /* left/right children nodes */
- uintptr_t avl_pcb; /* parent, child_index, balance */
- };
- #endif
说这么多,以后再说freebsd的avl树咋用的吧。