0x01数据结构——C语言实现(树)

0x01数据结构——C语言实现(树)

树(tree):
一棵树是一些节点的集合。这个集合可以是空集;若非空,则一棵树由称为根(root)的节点r以及0个或多个非空的(子)树T1,T2,…,Tk组成,这些子树种每一颗的根都被来自根r的一条有向边(edge)所连接。每一棵子树的根叫做根r的儿子(child),而r是每一棵子树的根的父亲(parent)。

从节点n1到节点nk的路径(path)定义为节点n1,n2,…,nk的一个序列,使得对于1i<k,节点ni是节点ni+1的父亲。这个路径的长(length)为该路径上的变得条数,即k-1.从每一个节点到它自己有一条长为0的路径。在一颗树中从根到每一个节点恰好存在一条路径。

对任意节点nini的深度(depth)为从根到ni的唯一路径的长。因此,根的深度为0。ni的高(height)是从ni到一片树叶的最长路径的长。因此所有树叶的高度都是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;
}
posted @   main_c  阅读(566)  评论(0编辑  收藏  举报
编辑推荐:
· 从 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)
点击右上角即可分享
微信分享提示