1. 介绍
Key-value 键值对貌似有用红黑书实现的(或者使用hash表实现,二者各有优劣),关于红黑树的详细介绍可以参看 http://blog.csdn.net/v_JULY_v/article/details/6105630
红黑树必须满足的规则:
- 所有节点都有颜色,要么红色,要么黑色
- 根节点是黑色,所有叶子节点也是黑色
- 叶子节点中不包含数据
- 非叶子节点都有2个子节点
- 如果一个节点是红色,那么它的父节点和子节点都是黑色的(黑节点无此要求!)
- 从任何一个节点开始,到其下叶子节点的路径中都包含相同数目的黑节点
根据规则,可以知道:
- 红黑树中最长的路径就是红黑交替的路径,最短的路径是全黑节点的路径,再加上根节点和叶子节点都是黑色,可以保证红黑树中最长路径的长度不会超过最短路径的2倍(这就是红黑树的平衡性,并不是绝对平衡)
以下红黑树的实现摘自 linux2.6.34 版本(是不是一棵二叉搜索树是由使用者决定)
2. rbtree.h
/* linux/include/linux/rbtree.h */
#ifndef _LINUX_RBTREE_H
#define _LINUX_RBTREE_H
//stddef.h里面有NULL和offsetof的定义
#include <stddef.h>
//vs下的话aligned那里是加 #pragma pack(4)
struct rb_node
{
unsigned long rb_parent_color; //存储父节点的地址(low 2 bit 为 0) + 本节点的 r/b 信息(就放在 low 2 bit 中)
#define RB_RED 0
#define RB_BLACK 1
struct rb_node *rb_right;
struct rb_node *rb_left;
} __attribute__((aligned(sizeof(long)))); //4bytes对齐,因此节点地址的 low 2 bit 必然为 0
struct rb_root
{
struct rb_node *rb_node;
};
//获取本节点的父节点的地址
#define rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~3))
//获取本节点的 color
#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)
//设置本节点的父节点(为 p)
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;
}
//设置本节点的color
static inline void rb_set_color(struct rb_node *rb, int color)
{
rb->rb_parent_color = (rb->rb_parent_color & ~1) | color;
}
//将 一个含有NULL指针的结构体 强制转换为 struct rb_root
#define RB_ROOT (struct rb_root) { NULL, }
//下面这个宏摘自include/linux/kerne.h
//#define container_of(ptr, type, member) ({ \
// const typeof( ((type *)0)->member ) *__mptr = (ptr); \
// (type *)( (char *)__mptr - offsetof(type,member) );})
//这是jensen的写法,反倒好用,且不用再搞一个offsetof了,上面的写法在vs环境可能会不认识
#define container_of(node, container, member) \
(container *) (((char*) (node)) - ((unsigned long) &((container *)0)->member))
#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))
extern void rb_insert_color(struct rb_node *, struct rb_root *);
extern void rb_erase(struct rb_node *, struct rb_root *);
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 *);
extern void rb_replace_node(struct rb_node *victim, struct rb_node *new,
struct rb_root *root);
//vs下inline写作__inline
//将node节点插入 由parent 和 rb_link 决定的那个位置
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; //parent地址low 2 bit为0,因此默认红色节点
node->rb_left = node->rb_right = NULL;
*rb_link = node;
}
#endif /* _LINUX_RBTREE_H */
3. rbtree.c
rbtree.c.part1 之 __rb_rotate_left()
/* linux/lib/rbtree.c */
#include "rbtree.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)) //1.B的右为E, E为NULL的话就没必要设置了
rb_set_parent(right->rb_left, node); //2.E的父设为B
right->rb_left = node; //3.D的左设为B
rb_set_parent(right, parent); //4.D的父设为A
if (parent)
{
if (node == parent->rb_left) //5.A的左设为D
parent->rb_left = right;
else
parent->rb_right = right; //5.(or)A的右设为D
}
else //若B原来就是root,(A为NULL)
root->rb_node = right;
rb_set_parent(node, right); //6.B的父设为D
}
rbtree.c.part2 之 __rb_rotate_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)) //1.B的左设为F
rb_set_parent(left->rb_right, node); //2.F的父设为B
left->rb_right = node; //3.C的右设为B
rb_set_parent(left, parent); //4.C的父设为A
if (parent)
{
if (node == parent->rb_right) //5.A的右设为C
parent->rb_right = left;
else
parent->rb_left = left; //5.A的左设为C
}
else
root->rb_node = left; //若B原来就是root,(A为NULL)
rb_set_parent(node, left); //6.B的父设为C
}
rbtree.c.part3 之 rb_insert_color()
//此函数并不插入节点, 只是作为插入节点完毕之后最为关键的调整(包括高度和颜色)
//插入节点的操作由用户完成,用户会将新增节点插入为叶子节点(在红黑树的概念里,NULL才是叶子节点,那他就不叫叶子节点),而本函数可能将其调整为非叶子节点
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)) //默认插入红节点,因此若父节点为黑,其实不需任何调整(A位置)
{ //进入这里说明是插入到了B线上的某个位置
gparent = rb_parent(parent);
if (parent == gparent->rb_left) //uncle在右
{
{
register struct rb_node *uncle = gparent->rb_right;
if (uncle && rb_is_red(uncle)) //uncle在右,uncle为红
{
rb_set_black(uncle); //uncle和parent必然在一左一右两个子树上,
rb_set_black(parent); //同时黑化不影响本<祖父子三代>的平衡,但<三代>整体黑节点多了
rb_set_red(gparent); //这样<三代>颜色正好了,但 祖 与 祖的父亲 同为红!这刚好与在gp下插入
node = gparent; //红色节点的case相同,成为一个 递归/迭代 问题
continue;
}
}
//uncle在右,uncle为黑
if (parent->rb_right == node) //若是LR型,则先转换为LL型
{
register struct rb_node *tmp;
__rb_rotate_left(parent, root);
tmp = parent;
parent = node;
node = tmp;
}
//走到这里一定是LL型
rb_set_black(parent);
rb_set_red(gparent);
__rb_rotate_right(gparent, root);
} else { //uncle在左边
{
register struct rb_node *uncle = gparent->rb_left;
if (uncle && rb_is_red(uncle)) //uncle在左,uncle为红
{
rb_set_black(uncle);
rb_set_black(parent);
rb_set_red(gparent);
node = gparent;
continue;
}
}
//uncle在左,uncle为黑
if (parent->rb_left == node) //若是RL型,则先转换为RR型
{
register struct rb_node *tmp;
__rb_rotate_right(parent, root);
tmp = parent;
parent = node;
node = tmp;
}
//走到这里一定是RR型
rb_set_black(parent);
rb_set_red(gparent);
__rb_rotate_left(gparent, root);
}
}
rb_set_black(root->rb_node);
}
rbtree.c.part4 之 __rb_erase_color() and rb_erase()
static void __rb_erase_color(struct rb_node *node, struct rb_node *parent, struct rb_root *root) //case A 就不会进到这个函数中
{
struct rb_node *other;
while ((!node || rb_is_black(node)) && node != root->rb_node) //此节点不应该是根节点,且此节点为黑 (为NULL也是黑。所以case C出局)
{
if (parent->rb_left == node) //此node为左子树
{
other = parent->rb_right;
if (rb_is_red(other)) //case B5(然后case B5就转化为B1 B2 B3 B4中的一个了)
{
rb_set_black(other);
rb_set_red(parent);
__rb_rotate_left(parent, root);
other = parent->rb_right;
} //走到这里只可能是 case B1 B2 B3 B4中的一种了
if ((!other->rb_left || rb_is_black(other->rb_left)) &&
(!other->rb_right || rb_is_black(other->rb_right))) //如果SL与SR均为黑(为NULL也是黑哦),caseB1/B2
{
rb_set_red(other);
node = parent; //继续向上迭代,caseB1还会while继续,caseB2就不会再进while了
parent = rb_parent(node);
}
else //case B3/B4
{
if (!other->rb_right || rb_is_black(other->rb_right)) //SR为黑,caseB4(下面一顿操作B4就变成了B3)
{
rb_set_black(other->rb_left);
rb_set_red(other);
__rb_rotate_right(other, root);
other = parent->rb_right;
} //走到这里只可能是caseB3了
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 //此node为右子树,和左子树的case对称
{
other = parent->rb_left;
if (rb_is_red(other)) //case B5
{
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 //左右子树均存在时,用此节点的下一个节点(中序遍历)替代此节点,之后将那个节点删除(又成了上面俩分支的case)
{
struct rb_node *old = node, *left;
node = node->rb_right;
while ((left = node->rb_left) != NULL) //此即找到此节点中序遍历的next节点(所谓上位节点),用它替换原节点没问题
node = left;
//下面next节点像八爪蜘蛛一样爬到待删节点处,给整个树造成一直好像消失的是next节点一样的假象
if (rb_parent(old)) { //待删节点的父亲认 上位的next节点 为子(架空待删节点step1)
if (rb_parent(old)->rb_left == old)
rb_parent(old)->rb_left = node; //
else
rb_parent(old)->rb_right = node; //
} else //要删root节点啊
root->rb_node = node;
//记录八爪蜘蛛原来位置的parent,children和color
child = node->rb_right; //next肯定没有左子树,但可能会有右子树,(右子树也会上位,填next节点的坑)
parent = rb_parent(node);
color = rb_color(node);
if (parent == old) { //这个位置已经要被next节点架空了,也说明找next节点的时候根本没向左找
parent = node;
} else { //next节点右子树上位填next节点的坑
if (child)
rb_set_parent(child, parent); //step2
parent->rb_left = child; //step3
node->rb_right = old->rb_right; //step4
rb_set_parent(old->rb_right, node); //step5
} //到此原来next节点已经没有他的位置了
node->rb_parent_color = old->rb_parent_color; //step6
node->rb_left = old->rb_left; //step7
rb_set_parent(old->rb_left, node); //step8
//同时也就相当于原待删节点至此已经完全被架空了
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: //走到这一步,则node已经从树中被删除了,删除了的节点原来的
if (color == RB_BLACK) //parent和child信息交给__rb_erase_color函数用于 rebalance(case A不会调用此函数)
__rb_erase_color(child, parent, root);
}
rbtree.c.part5 之 others
/*
* 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;
}
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_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;
}
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;
}
void rb_replace_node(struct rb_node *victim, struct rb_node *new,
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;
else
parent->rb_right = new;
} else {
root->rb_node = new;
}
if (victim->rb_left)
rb_set_parent(victim->rb_left, new);
if (victim->rb_right)
rb_set_parent(victim->rb_right, new);
/* Copy the pointers/colour from the victim to the replacement */
*new = *victim;
}
4. 一个使用红黑树的例子
(从中可以看到红黑树一般都实现为二叉搜索树,即left和right是有大小关系约束的。但这一点其实是靠使用者来保证的)。
用tree实现一个key-value map(红黑树实现map与hash表实现map各有优劣)。每一个Node除了包含 rb_node 还包含key(string)和value(int)。添加键值对的时候按照 key (string)的 ASCII 按序插入,查找的时候利用 strcmp 进行查找,若找到则返回 value。但貌似 linux里面的 idr不是这样实现的,她是一个32叉树,why? 效率高? 这里也讲解了一个如何使用红黑树的例子.
commonTree.h
#ifndef COMMON_TREE_H
#define COMMON_TREE_H
#include "rbtree.h"
typedef struct
{
struct rb_node node;
void *kdata; //按 kdata 为关键字组成二叉排序树
void *vdata; //custom app data, maybe a structure
}cTreeNode,*cTreeNodeId;
typedef struct
{
int total;
int (*cmp)(const void *p1,const void *p2); //p1<p2 return <0
struct rb_root root;
}cTreeManager,*cTree;
cTree cTreeCreate(int (*cmp)(const void *p1,const void *p2));
//这个主要是想配合 cTreeEraseFromNodeId 函数使用的
cTreeNodeId cTreeSearch(cTree ctree,void *kdata);
void *getVdataFromNodeId(cTreeNodeId id);
void *getKdataFromNodeId(cTreeNodeId id);
//如果vdata指向自定义的数据结构,则返回update之前的vdata,必须释放,否则可能内存泄漏
//vdata不需要释放的则可以不用关心free操作及返回的void*
void *cTreeInsert(cTree ctree,void *kdata,unsigned int kdataSize,void *vdata);
void *cTreeEraseFromNodeId(cTree ctree,cTreeNodeId *pid);
void *cTreeErase(cTree ctree,void *kdata);
int cTreeMap(cTree ctree,void apply(void *k,void **pv,void *cl), void *cl);
int cTreeMap2(cTree ctree,void apply(void *k,void **x,void *cl,int lev), void *cl);
int cTreeDestroy(cTree *pctree);
#endif
commonTree.c
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "commonTree.h"
//默认是按照 kdata 指针值排序(即key的地址值)
static int cmp_default(const void *p1,const void *p2)
{
return ((unsigned int)p1 - (unsigned int)p2);
}
cTree cTreeCreate(int (*cmp)(const void *p1,const void *p2))
{
cTree p = (cTreeManager *)malloc(sizeof(cTreeManager));
if(!p)
return NULL;
p->total = 0;
p->root = RB_ROOT; //init rb tree
p->cmp = (cmp == NULL) ? cmp_default : cmp; //init rb tree
return p;
}
cTreeNodeId cTreeSearch(cTree ctree,void *kdata)
{
cTreeNode *pTreeNode = NULL;
int cmpRes = 0;
struct rb_root *pRoot = &(ctree->root); //the root, including a pointer to rb_node
struct rb_node *pNode = pRoot->rb_node; //the first node
while(pNode != NULL)
{
pTreeNode = container_of(pNode,cTreeNode,node);
cmpRes = (*(ctree->cmp))(kdata,pTreeNode->kdata);
if(cmpRes < 0)
{
pNode = pNode->rb_left;
}
else if(cmpRes > 0)
{
pNode = pNode->rb_right;
}
else
{
return pTreeNode; //cTreeNodeId 就是一个 cTreeNode*
}
}
return NULL;
}
void *getKdataFromNodeId(cTreeNodeId id)
{
return (id->kdata);
}
void *getVdataFromNodeId(cTreeNodeId id)
{
return (id->vdata);
}
void *cTreeInsert(cTree ctree,void *kdata,unsigned int kdataSize,void *vdata)
{
void *oldVdata = NULL;
cTreeNode *pTreeNode = NULL;
int cmpRes = 0;
struct rb_root *pRoot = &(ctree->root); //the root, including a pointer to rb_node
struct rb_node **ppNode = &(pRoot->rb_node); //这里参见 rbtree.h 那里的第二张图,这里是想改变指针的指向 而不是改变指针指向的那个值
struct rb_node *pParent = NULL;
while(*ppNode)
{
pTreeNode = container_of(*ppNode,cTreeNode,node);
pParent = *ppNode;
cmpRes = (*(ctree->cmp))(kdata,pTreeNode->kdata);
if(cmpRes < 0)
{
ppNode = &(*ppNode)->rb_left;
}
else if(cmpRes > 0)
{
ppNode = &(*ppNode)->rb_right;
}
else
{
//如果有相同的 key 要插入,返回之前的old vdata,用户 MUST 进行必要的 释放 操作 !!!
//我们使用的 kdata 有没有可能存在泄露?
//case.1: kdata 通过malloc分配的,那么更新后的 pTreeNode->kdata 仍然指向他,没有丢失
//case.2: kdata 是vdata指向结构体的某个成员,那么更新后的 pTreeNode->kdata 地址失效
//这样太复杂了,关键是不可控制,因此我们无论如何自己保存一份kdata!,这样的话,这里的kdata无论无何都是有效的(只是我们不必再memcpy一次了)
oldVdata = pTreeNode->vdata;
pTreeNode->vdata = vdata;
return oldVdata;
}
}
//malloc a tree node for (k,v)
cTreeNode *pTargetTreeNode = (cTreeNode *)malloc(sizeof(cTreeNode)+kdataSize+1);
if(!pTargetTreeNode)
return NULL;
pTargetTreeNode->kdata = (void *)(pTargetTreeNode+1); //kdata的值紧跟着节点存放
memset(pTargetTreeNode->kdata,0,kdataSize+1);
memcpy(pTargetTreeNode->kdata,kdata,kdataSize); //我们默认 kdata 指向的地址是一个有效的值!! 不允许 "(void *)i" 这样的玩法!!
pTargetTreeNode->vdata = vdata;
rb_link_node(&pTargetTreeNode->node, pParent,ppNode); //first, link this node to rbTree
rb_insert_color(&pTargetTreeNode->node, pRoot); //rebalance
ctree->total++;
return NULL;
}
//这个只是删除(释放) cTreeNode,其 vdata 指向的内存需要自己来释放!
void *cTreeEraseFromNodeId(cTree ctree,cTreeNodeId *pid)
{
void *oldVdata = NULL;
struct rb_root *pRoot = &(ctree->root); //the root, including a pointer to rb_node
if(!pid || !(*pid))
return NULL;
cTreeNode *pTreeNode = *pid;
oldVdata = pTreeNode->vdata;
rb_erase(&pTreeNode->node,pRoot); //just remove from rbtree relationship
free(pTreeNode); //if pTreeNode->pdata pointer to a struct ,you MUST free yourself !!
ctree->total--;
*pid = NULL;
return oldVdata; //留待用户释放的 vdata (如有必要释放)
}
//equals to "search and erase by id" operation
void *cTreeErase(cTree ctree,void *kdata)
{
void *oldVdata = NULL;
cTreeNode *pTreeNode = NULL;
int cmpRes = 0;
struct rb_root *pRoot = &(ctree->root); //the root, including a pointer to rb_node
struct rb_node *pNode = pRoot->rb_node; //the first node
while(pNode != NULL)
{
pTreeNode = container_of(pNode,cTreeNode,node);
cmpRes = (*(ctree->cmp))(kdata,pTreeNode->kdata);
if(cmpRes < 0)
{
pNode = pNode->rb_left;
}
else if(cmpRes > 0)
{
pNode = pNode->rb_right;
}
else
{
oldVdata = pTreeNode->vdata;
rb_erase(pNode,pRoot);
free(pTreeNode); //if pTreeNode->pdata pointer to a struct ,you MUST free yourself !!
ctree->total--;
return oldVdata; //留待用户释放的 vdata (如有必要释放)
}
}
return NULL;
}
int cTreeMap(cTree ctree,void apply(void *k,void **pv,void *cl), void *cl)
{
struct rb_root *pRoot = &(ctree->root); //the root, including a pointer to rb_node
struct rb_node *pNode = NULL;
cTreeNode *pTreeNode = NULL;
//(其实就是while迭代实现的中序遍历),rb_first()找到的node也是中序遍历意义上的第一个
for(pNode = rb_first(pRoot);pNode;pNode = rb_next(pNode))
{
pTreeNode = container_of(pNode,cTreeNode,node);
//printf("%d,",pMgrNode->value);
apply(pTreeNode->kdata,&pTreeNode->vdata,cl);
}
return 0;
}
static int cTreeMapInternal(struct rb_node *pNode,void apply(void *k,void **x,void *cl,int lev), void *cl, int level)
{
cTreeNode *pTreeNode = NULL;
if(!pNode)
return 0;
if(pNode->rb_left)
cTreeMapInternal(pNode->rb_left,apply,cl,level+1);
//else
// apply(NULL,NULL,cl,level+1);
//mid order access
pTreeNode = container_of(pNode,cTreeNode,node);
apply(pTreeNode->kdata,&pTreeNode->vdata,cl,level);
if(pNode->rb_right)
cTreeMapInternal(pNode->rb_right,apply,cl,level+1);
//else
// apply(NULL,NULL,cl,level+1);
return 0;
}
int cTreeMap2(cTree ctree,void apply(void *k,void **x,void *cl,int lev), void *cl)
{
struct rb_root *pRoot = &(ctree->root); //the root, including a pointer to rb_node
struct rb_node *pNode = pRoot->rb_node; //the first node
return cTreeMapInternal(pNode,apply,cl,0);
}
//调用本 cTreeDestroy 前,应该先调用 cTreeMap 释放掉所有的 vdata 指向的内存
int cTreeDestroy(cTree *pctree)
{
if(!pctree || !(*pctree))
return 0;
cTree ctree = *pctree;
struct rb_root *pRoot = &(ctree->root); //the root, including a pointer to rb_node
struct rb_node *pNode = NULL;
struct rb_node *pNodeTmp = NULL;
cTreeNode *pTreeNodeTmp = NULL;
pNode = rb_first(pRoot);
while(pNode)
{
pNodeTmp = pNode;
pNode = rb_next(pNode);
pTreeNodeTmp = container_of(pNodeTmp,cTreeNode,node);
rb_erase(pNodeTmp,pRoot);
free(pTreeNodeTmp); //if pTreeNode->pdata pointer to a struct ,you MUST free yourself !!
ctree->total--;
}
free(ctree);
*pctree = NULL;
return 0;
}