0x01数据结构——C语言实现(树)
0x01数据结构——C语言实现(树)
树(tree):
一棵树是一些节点的集合。这个集合可以是空集;若非空,则一棵树由称为根(root)的节点r以及0个或多个非空的(子)树,,…,组成,这些子树种每一颗的根都被来自根r的一条有向边(edge)所连接。每一棵子树的根叫做根r的儿子(child),而r是每一棵子树的根的父亲(parent)。
从节点到节点的路径(path)定义为节点,,…,的一个序列,使得对于,节点是节点的父亲。这个路径的长(length)为该路径上的变得条数,即k-1.从每一个节点到它自己有一条长为0的路径。在一颗树中从根到每一个节点恰好存在一条路径。
对任意节点,的深度(depth)为从根到的唯一路径的长。因此,根的深度为0。的高(height)是从到一片树叶的最长路径的长。因此所有树叶的高度都是0。一棵树的高等于它的根的高。一棵树的深度等于它的最深的树叶的深度,该深度总是等于这棵树的高。
树的C语言实现:
tree.h
/* 树(tree): 一棵树是一些节点的集合。 这个集合可以是空集;若非空,则一棵树由称为根(root)的节点r以及0个或多个非空的(子) 树T1,T2,...,Tk组成,这些子树种每一颗的根都被来自根r的一条有向边(edge)所连接。 每一棵子树的根叫做根r的儿子(child),而r是每一棵子树的根的父亲(parent)。 root / / | \ ... \ T1 T2 T3 T4 ... Tk */ #ifndef TREE_H #define TREE_H /* 树的节点用孩子兄弟表示法来存储。 */ typedef enum { false = 0, true } BOOL; struct node; typedef struct node node; typedef node *tree; typedef node *pos; //根据先序遍历创建一棵树 //输入数组规定如下:如果一个节点没有孩子,他后面接‘#’,如果没有兄弟接‘$’,如果两种情况都有接“%” tree create_tree_preorder(int v[], int left, int right); //将一颗树置空 tree make_empty(tree T); //判断树是不是空的 BOOL is_empty(tree T); //为节点p添加孩子节点x void add_child(node *p, int x); //根据先序遍历数组来创建树(先序遍历数组中用'#'来表示空节点) tree create_by_preorder(int n[], int N); //先序遍历树 void preorder_traversal(tree T); //以数组形式打印 //数组规定如下:如果一个节点没有孩子,他后面接‘#’,如果没有兄弟接‘$’,如果两种情况都有接“%” void preorder_traversal1(tree T); //后序遍历 void postorder_traversal(tree T); //寻找节点x的位置 pos search(int x, tree T); //取出节点p的值 int retrieve_p(pos p); //以层次方式打印输出 void print_tree(tree T); void output(tree T, int i); #endif
tree.c
#include <stdio.h> #include <stdlib.h> #include "tree.h" struct node { int val; struct node *child; struct node *bro; }; /* struct node; typedef struct node node; typedef node *tree; typedef node *pos; */ //根据先序遍历创建一棵树, 层与层之间 //输入数组规定如下:如果一个节点没有孩子,他后面接‘#’,如果没有兄弟接‘$’,如果两种情况都有接“%” tree create_tree_preorder(int v[], int left, int right) { if(left>right || v==NULL) return NULL; tree T = NULL; int i = left; if(v[i]!='#' && v[i]!='$' && v[i]!='%') { T = (node *)malloc(sizeof(node)); T->val = v[i]; i++; if(v[i] == '#') { i++; T->child = NULL; T->bro = create_tree_preorder(v, i, right); } else if(v[i] == '$') { i++; T->bro = NULL; T->child = create_tree_preorder(v, i, right); } else if(v[i] == '%') { i++; T->bro = NULL; T->child = NULL; } else { T->child = create_tree_preorder(v, i, right); while(v[i]!='%') { i++; } i++; T->bro = create_tree_preorder(v, i, right); } } return T; } //将一颗树置空 tree make_empty(tree T) { if(T!=NULL) { make_empty(T->child); make_empty(T->bro); printf("free node with value %d\n", T->val); free(T); T = NULL; } return T; } //判断树是不是空的 BOOL is_empty(tree T) { return T == NULL; } //为节点p添加孩子节点x void add_child(node *p, int x) { node *tmp = p->child; if(tmp == NULL) { tmp = (node *)malloc(sizeof(node)); tmp->val = x; tmp->child = NULL; tmp->bro = NULL; } else { while(tmp->bro != NULL) { tmp = tmp->bro; } tmp->bro = (node *)malloc(sizeof(node)); tmp->bro->val = x; tmp->bro->child = NULL; tmp->bro->bro = NULL; } } //先序遍历树 void preorder_traversal(tree T) { if(T != NULL) { printf("%d", T->val); tree tmp; tmp = T->child; while(tmp!=NULL) { preorder_traversal(tmp); tmp = tmp->bro; } } } //输出一种可以回复成原始树的先序遍历数组 //数组规定如下:如果一个节点没有孩子,他后面接‘#’,如果没有兄弟接‘$’,如果两种情况都有接“%” void preorder_traversal1(tree T) { tree tmp; if(T!=NULL) { printf("%d",T->val); if(T->child == NULL && T->bro != NULL) { printf("#"); } if(T->child != NULL && T->bro == NULL) { printf("$"); } if(T->child == NULL && T->bro == NULL) { printf("%%"); } tmp = T->child; while(tmp!=NULL) { preorder_traversal1(tmp); tmp = tmp->bro; } } } //后序遍历 void postorder_traversal(tree T) { if(T != NULL) { tree tmp; tmp = T->child; while(tmp!=NULL) { postorder_traversal(tmp); tmp = tmp->bro; } printf("%d", T->val); } } //寻找节点x的位置 pos search(int x, tree T) { if(T!=NULL) { if(T->val == x) { return T; } else { tree tmp = T->child; while(tmp!=NULL) { if((T=search(x, tmp)) != NULL) { break; } tmp = tmp->bro; } } } return T; } //取出节点p的值 int retrieve_p(pos p) { return p->val; } //以层次方式打印输出 void print_tree(tree T) { output(T,0); } void output(tree T, int i)//i用来记录节点的深度 { if(T != NULL) { for(int j = 0; j<i; j++) { printf("\t"); } printf("%d\n", T->val); tree tmp; tmp = T->child; i++; while(tmp!=NULL) { output(tmp,i);//输出各个子树 tmp = tmp->bro; } } }
main.c
#include <stdio.h> #include <stdlib.h> #include "tree.h" struct node { int val; struct node *child; struct node *bro; }; int main() { tree T, T1; pos tmp; int A[16] = {1,'$',2,8,'#',9,'%',3,5,'%',4,'$',6,'#',7,'%'}; //print_tree(T); //preorder_traversal1(T); //printf("\n"); //postorder_traversal(T); //printf("\n"); //pos t = search(2,T); //printf("%d\n", t->val); T1 = create_tree_preorder(A, 0, 15); print_tree(T1); preorder_traversal(T1); printf("\n"); tmp = make_empty(T1); printf("%d\n", is_empty(tmp)); print_tree(tmp); postorder_traversal(tmp); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)