一种多叉树的实现,提供树形结构打印,树转表输出等功能

Posted mic-chen

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一种多叉树的实现,提供树形结构打印,树转表输出等功能相关的知识,希望对你有一定的参考价值。

多叉树的变种有很多很多种,根据不同的应用需要,对树节点的封装,对树的查找等操作的要求各不一样。

在PC数据库中,b-tree比较多,网上也较多可参考的代码,但是在嵌入式软件中,这种可能过于复杂,也不需要那么多的节点管理,

因此在效率上也不是很重视,本代码基于比较简单的实现,目的是实现对线程树的管理。

其中还有很多有待完善,特别是对用户数据的挂接的void *data的使用。

tree.h

#define SUB_TASK_MAX                32
#define TASK_NAME_LEN_MAX           32



// 采用数组方式实现,如果节点数量较多,操作频繁可优化为链表
// 所有查找均采用层次优先遍历
typedef struct ak_tree_node
{
    long         id;
#if 1 
    //int                   level;
    struct ak_tree_node    *parent;
    int                     n_child;       // number of children
    struct ak_tree_node*    children[SUB_TASK_MAX];
#else
    //struct ak_tree_node    *parent;
    //struct ak_tree_node    *sibling_prev;
    //struct ak_tree_node    *first_child;
    //struct ak_tree_node    *sibling;
#endif

    void *data;
}ak_tree_node_t;


typedef struct ak_tree_node_list
{
    ak_tree_node_t *data;
    struct ak_tree_node_list *next;
}ak_tree_node_list_t;

typedef int (*TREE_GET_NAME_CB)(long id,char *name);

typedef struct ak_tree
{
    ak_tree_node_t root;

    char init_flag;

    int  stack_point;
    char stack_buf[SUB_TASK_MAX][TASK_NAME_LEN_MAX];

    T_hSemaphore    lock;

    TREE_GET_NAME_CB get_name;
}ak_tree_t;


ak_tree_node_t* ak_tree_find_node(ak_tree_t *tree,long id);

int ak_tree_insert_node_as_child(ak_tree_t *tree, long id_parent, long id_child);
int ak_tree_insert_node_as_sibling(ak_tree_t *tree, long id_sibling, long id_child);

int ak_tree_remove_node(ak_tree_t *tree, long id);
ak_tree_t *ak_tree_create(void);

int ak_tree_destroy(ak_tree_t *tree);
int ak_tree_init(ak_tree_t *tree,long id_root,TREE_GET_NAME_CB get_name);

// note:调用完后,务必调用ak_tree_release_list 释放内存
ak_tree_node_list_t* ak_tree_to_list(ak_tree_t *tree, long id);
ak_tree_node_list_t* ak_tree_get_children_list(ak_tree_t *tree, long id);
int ak_tree_release_list(ak_tree_node_list_t *list);


/*
打印输出链式结构

IDLE--ringMai--D_UART1--mcuRecv--meMain--D_CAM--command
*/
int ak_tree_print_list(ak_tree_t *tree,long id);

/*
打印输出树形结构

CMain--IDLE
     |-ringMai--D_UART1
     |        |-WifiCon--MOAL_WO
     |        |        `-tcpip_t
     |        |-TCtrCon
     |        `-ringHea
     `-command
*/
int ak_tree_print(ak_tree_t *tree, long id);

  

tree.c

static ak_tree_node_t *create_node(void)
{
    ak_tree_node_t *node = (ak_tree_node_t *)Fwl_Malloc(sizeof(ak_tree_node_t));

    node->n_child = 0;
    memset(&node->children,0,SUB_TASK_MAX);
    return node;
}
static void *destroy_node(ak_tree_node_t *node)
{
    return Fwl_Free(node);
}

// search by name recursion
static ak_tree_node_t* search_node_r(ak_tree_node_t* node,long id)
{
    ak_tree_node_t* temp = NULL;
    int i = 0;

    if (node != NULL)  {
        if (id == node->id) {
            temp = node;
        } else {
            for (i = 0; i < node->n_child && temp == NULL/*如果temp不为空,则结束查找*/; ++i)
            {
                temp = search_node_r(node->children[i],id); // 递归查找子节点
            }
        }
    }
    return temp; // 将查找到的节点指针返回,也有可能没有找到,此时temp为NULL
}

static int insert_node(ak_tree_t *tree,ak_tree_node_t* parent,long id) 
{
    int ret = 0;

    if(0 == tree->lock) {
        tree->lock = AK_Create_Semaphore(1, AK_PRIORITY);
        if (tree->lock !=AK_INVALID_SUSPEND){
            printf("task tree Create Semaphore ok
");
            return 0 ; 
        } else {
            tree->init_flag = 0;
            printf("task tree Create Semaphore fail
");
            return -1;
        } 
    }

    AK_Obtain_Semaphore(tree->lock, AK_SUSPEND);
    if(NULL != parent) {
        ak_tree_node_t *child = create_node();
        child->id = id;
        child->parent = parent;
        parent->children[parent->n_child] = child;
        parent->n_child++;
    } else {
        printf("insert node, parent id null
");
    }
    AK_Release_Semaphore(tree->lock);
    return ret;
}


ak_tree_node_list_t* tree_to_list_r(ak_tree_t *tree, ak_tree_node_t *head)
{   
    int i;
    //ak_tree_node_t* head = NULL;
    ak_tree_node_list_t *list;

    // 查找节点
    if(NULL == head) {
        return NULL;
    }
    
    // 申请内存并初始化
    list = Fwl_Malloc(sizeof(ak_tree_node_list_t));
    list->data = NULL;
    list->next = NULL;

    ak_tree_node_list_t *list_temp = list;
    list_temp->data = head;
    list_temp->next = NULL;

    // 递归子节点
    for (i = 0; i < head->n_child; i++) {
        list_temp->next = tree_to_list_r(tree,head->children[i]);
        // 更新list_temp,跳到最后一个
        while(NULL != list_temp->next) {
            list_temp = list_temp->next;
        }
    }
           
    return list;
}

static void get_node_name(ak_tree_t *tree,long id,char *name)
{
    if(NULL != tree->get_name) {
        tree->get_name(id,name);
    } else {
        name[0] = 0;
    }
}

static int tree_print_node_r(ak_tree_t *tree,ak_tree_node_t *node)
{
    char i;
    char j;
    int offset_flag = 0;
    T_S8 name[16];
    T_S8 prefix[8];

    int name_len = 0;
    get_node_name(tree,node->id,name);
    name_len = strlen(name);
    prefix[0] = 0;
    
    // 利用递归,依次入栈路径上各父节点的打印信息
    ak_tree_node_t *parent = node->parent;
    i = 0;
    if(0 != tree->stack_point) {
        // 前缀 "--" or "|-" or "--"
        if(NULL == parent) {
            printf("parent is null,should not enter here
");
            return -1;
        }
        
        if (node == parent->children[0]) {
            prefix[i] = ‘-‘;
            tree->stack_buf[tree->stack_point][i++] = ‘|‘;
            offset_flag = 0;
        } else if(node == parent->children[parent->n_child-1]){
            prefix[i] = ‘`‘;
            tree->stack_buf[tree->stack_point][i++] = ‘ ‘;
            offset_flag = 1;
        } else {
            prefix[i] = ‘|‘;
            tree->stack_buf[tree->stack_point][i++] = ‘|‘;
            offset_flag = 1;
        }
        prefix[i] = ‘-‘;
        tree->stack_buf[tree->stack_point][i++] = ‘ ‘;
    }
    // name域
    for(j = i; j < name_len+i; j++) {
        tree->stack_buf[tree->stack_point][j] = ‘ ‘;
    }
    tree->stack_buf[tree->stack_point][j] = ‘‘;
    tree->stack_point++;

    // 打印偏移
    if(offset_flag) {
        for(j = 0; j < tree->stack_point-1; j++) {
            printf("%s",tree->stack_buf[j]);
        }
    }
   
    // 打印本节点
    prefix[i] = ‘‘;
    printf("%s",prefix);
    printf("%s",name);
    if(0 == node->n_child) {
        printf("
");
    }

    for (i = 0; i < node->n_child; i++) {   
        // 递归子节点
        tree_print_node_r(tree,node->children[i]);
    }
    
    if(tree->stack_point > 0) {
        tree->stack_point--;
    }
}

//-------------------- tree api -----------------------

ak_tree_node_t* ak_tree_find_node(ak_tree_t *tree,long id)
{
    return search_node_r(&tree->root,id);
}

int ak_tree_insert_node_as_child(ak_tree_t *tree, long id_parent, long id_child)
{
    int ret = 0;
    ak_tree_node_t* parent = NULL;

    parent = search_node_r(&tree->root,id_parent);
    ret = insert_node(tree,parent,id_child);
    return ret;
}
int ak_tree_insert_node_as_sibling(ak_tree_t *tree, long id_sibling, long id_child)
{
    int ret = 0;
    ak_tree_node_t* sibling = NULL;

    sibling = search_node_r(&tree->root,id_sibling);
    ret = insert_node(tree,sibling->parent,id_child);
    return ret;
}

int ak_tree_remove_node(ak_tree_t *tree, long id)
{
    int ret = 0;
    ak_tree_node_t* temp = NULL;
    int i;
    
    temp = search_node_r(&tree->root,id);
    AK_Obtain_Semaphore(tree->lock, AK_SUSPEND);
    if(NULL != temp) {      
        ak_tree_node_t *parent = temp->parent;
        //printf("ak_tree_remove_node parent=%0x n_child=%d",parent,parent->n_child);
        if(parent->n_child > 0) {
            for(i = 0; i < parent->n_child;i++) {
                if(temp == parent->children[i]) break;
            }
            if(i < parent->n_child) {
                for(;i < parent->n_child;i++) {
                    parent->children[i] = parent->children[i+1];
                }
                destroy_node(temp);
                parent->n_child--;
            } else {
                ret = -1;
                printf("remove tree node error: match child fail
");
            }
        } else {
            ret = -2;
            printf("remove tree node error : chilsren num is 0
");
        }
    }
    AK_Release_Semaphore(tree->lock);

    return ret;
}


ak_tree_t *ak_tree_create(void)
{
    ak_tree_t *tree = (ak_tree_t *)Fwl_Malloc(sizeof(ak_tree_t));
    return tree;
    
}

int ak_tree_destroy(ak_tree_t *tree)
{
     return Fwl_Free(tree);
}

int ak_tree_init(ak_tree_t *tree,long id_root,TREE_GET_NAME_CB get_name)
{
    memset(tree,0,sizeof(ak_tree_t));
    tree->root.id = id_root;
    tree->init_flag = 1;
    tree->get_name = get_name;

    // 不能在这里创建一个为1的信号量,否则系统崩溃,因为OS调度还没有启动??
#if 0
    //tree->lock = AK_Create_Semaphore(1, AK_PRIORITY); 
    if (tree->lock !=AK_INVALID_SUSPEND){
        printf("ak_tree_init ok
");
        tree->init_flag = 1;
        return 0 ; 
    } else {
        printf("ak_tree_init fail
");
        return -1;
    } 
#endif
}

ak_tree_node_list_t* ak_tree_to_list(ak_tree_t *tree, long id)
{
    ak_tree_node_t *head = search_node_r(&tree->root,id);
    return tree_to_list_r(tree,head);
}

ak_tree_node_list_t* ak_tree_get_children_list(ak_tree_t *tree, long id)
{
    ak_tree_node_list_t *self = NULL;
    ak_tree_node_list_t *children = NULL;

    ak_tree_node_t *head = search_node_r(&tree->root,id);
    self = tree_to_list_r(tree,head);
    if(NULL != self && NULL != self->next) {
        children = self->next;
    }
    return children;
}

int ak_tree_release_list(ak_tree_node_list_t *list)
{
    ak_tree_node_list_t *list_temp = NULL;

    while(NULL != list) {
        list_temp = list->next;
        Fwl_Free(list);
        list = list_temp;
    }
}


/*
打印输出链式结构

IDLE--ringMai--D_UART1--mcuRecv--meMain--D_CAM--command
*/
int ak_tree_print_list(ak_tree_t *tree,long id)
{
    T_S8 name[16];
    ak_tree_node_list_t *children_head;
    ak_tree_node_list_t *temp;

    
    children_head = ak_tree_get_children_list(tree,id);
    temp = children_head;
    printf("ak_tree_print_list:
");

    get_node_name(tree,temp->data->id, name);
    printf("%s",name);
    temp = temp->next;
    while(NULL != temp && temp->data != NULL) {
        get_node_name(tree,temp->data->id, name);
        printf("--%s",name);
        temp = temp->next;
    }
    ak_tree_release_list(children_head);

    printf("
");

}


/*
打印输出树形结构

CMain--IDLE
     |-ringMai--D_UART1
     |        |-WifiCon--MOAL_WO
     |        |        `-tcpip_t
     |        |-TCtrCon
     |        `-ringHea
     `-command
*/
int ak_tree_print(ak_tree_t *tree, long id)
{
    memset(tree->stack_buf,0,sizeof(tree->stack_buf));
    tree->stack_point = 0;

    ak_tree_t *head = search_node_r(&tree->root, id);
    tree_print_node_r(tree,head);
    printf("
");
}

  

 

以上是关于一种多叉树的实现,提供树形结构打印,树转表输出等功能的主要内容,如果未能解决你的问题,请参考以下文章

二叉树的树形结构打印

多叉树转二叉树+树形dp(codevs 1746 贪吃的九头龙 2002noi)

BZOJ1812riv(多叉树转二叉树,树形DP)

选课 树形DP+多叉树转二叉树+dfs求解答案

刷题总结——选课(ssoj树形dp+记忆化搜索+多叉树转二叉树)

多叉树结合JavaScript树形组件实现无限级树形结构(一种构建多级有序树形结构JSON(或XML)数据源的方法)