一种多叉树的实现,提供树形结构打印,树转表输出等功能
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)