红黑树

1. 介绍

Key-value 键值对貌似有用红黑书实现的(或者使用hash表实现,二者各有优劣),关于红黑树的详细介绍可以参看 http://blog.csdn.net/v_JULY_v/article/details/6105630

红黑树必须满足的规则:

  • 所有节点都有颜色,要么红色,要么黑色
  • 根节点是黑色,所有叶子节点也是黑色
  • 叶子节点中不包含数据
  • 非叶子节点都有2个子节点
  • 如果一个节点是红色,那么它的父节点和子节点都是黑色的(黑节点无此要求!)
  • 从任何一个节点开始,到其下叶子节点的路径中都包含相同数目的黑节点

rbtree

根据规则,可以知道:

  • 红黑树中最长的路径就是红黑交替的路径,最短的路径是全黑节点的路径,再加上根节点和叶子节点都是黑色,可以保证红黑树中最长路径的长度不会超过最短路径的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 */

img02
img02

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
}

img02img02img02

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
}

img02img02img02

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);
}

img02
img02img02
img02img02

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);
}

img02
img02img02
img02
img02img02img02img02img02

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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值