linux内核的红黑树RB_TREE和freebsd 8.0里面的AVL_TREE比较 之一 RB_TREE

这里不涉及到avl树和红黑树谁优谁劣,只是谈谈在两种实现的一些细节,以及最后给出一些性能比较。

这里先给出linux下面的红黑树的实现,因为linux下面的两个宏定义不好直接使用,原型如下:

修改如下:


语义可以认为不变的。

linux的RB_TREE源代码移植到vc上后,命名为:rb_tree.h, 如下:


实现文件移植之后,命名为rb_tree.cpp, 如下:

其实,可以看出,linux内核里面并没有提供直接可以用的insert delete 以及walk遍历的函数接口,linux提供的是最基本一个插入节点后的re-fixup, 删除后的re-fixup,以及walk需要的get-firt, get-next等等。

这里是需要自己提供插入,删除,以及walk函数的,相比freebsd的avl树,完全就是一步到位了,而且好用很多,这里不谈谁好用,然后举例简单说说怎么使用linux的基本的这些函数,晚点会比较二者在插入删除以及walk方面的优劣。

自己提供相应的一些接口了,时间有限随便写写:

应用头文件,rb_tree_main.h:

man文件:rb_tree_main.cpp


注意四点:

1、insert里面的双重指针,直接找到要插入的位置的父节点,省去了一堆赋值比如parent->left or right = p, p->parent 啥啥啥的,直接在父节点(叶子节点)的左或者右节点NULL的取一次地址,然后,地址上面写值,不细说了;

2、插入的节点应该动态分配,或者是已经静态分配好的多个节点

3、删除操作,内核提供的只是re-fixup,不会帮你释放内存的,我们要做的是找到这个节点,然后调用内核提供的rb_erase,把节点从rb树上移去,如果是动态分配,再释放之。

4、内核的红黑树是带有parent属性的,只是么有用指针,而是把parent和left和right子标记用了一个字段而已:


最低的一位用作了left和right的flag,最高的31位,用作存储parent指针的地址,这种rb树就要求插入的节点地址必须是偶数的,一般的cpu架构使得分配出来的内存都是偶数地址对齐的了,但是有些也会以奇数开始,比如ppc,就可能动态分配出一个节点就是从奇数地址开始的。只要是偶数地址开始那么地址的最低位一定是0了。

其实在3.0.1的内核里面是这种rb设计,在早期的内核里面rb_node就是另外一种设计了,是引入了parent指针的,比如2.6.11的内核的结构体设计如下:


其实在freebsd 8.0的avl树64位设计就是这种,32二位的设计类似于早些时候的内核的rb树的节点设计:


说这么多,以后再说freebsd的avl树咋用的吧。

你可能感兴趣的:(FreeBSD)