一種多叉樹的實現,提供樹形結構打印,樹轉表輸出等功能

多叉樹的變種有不少不少種,根據不一樣的應用須要,對樹節點的封裝,對樹的查找等操做的要求各不同。node

在PC數據庫中,b-tree比較多,網上也較多可參考的代碼,可是在嵌入式軟件中,這種可能過於複雜,也不須要那麼多的節點管理,數據庫

所以在效率上也不是很重視,本代碼基於比較簡單的實現,目的是實現對線程樹的管理。api

其中還有不少有待完善,特別是對用戶數據的掛接的void *data的使用。數組

tree.htcp

#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\n");
            return 0 ; 
        } else {
            tree->init_flag = 0;
            printf("task tree Create Semaphore fail\n");
            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\n");
    }
    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\n");
            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] = '\0';
    tree->stack_point++;

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

    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\n");
            }
        } else {
            ret = -2;
            printf("remove tree node error : chilsren num is 0\n");
        }
    }
    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\n");
        tree->init_flag = 1;
        return 0 ; 
    } else {
        printf("ak_tree_init fail\n");
        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:\n");

    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("\r\n");

}


/*
打印輸出樹形結構

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("\r\n");
}
相關文章
相關標籤/搜索