一、树
树型结构是一种一对多的结构,非线性的结构
二、树的基本要素
- 根节点(Root):树的顶层节点,没有父节点。
- 叶子节点(Leaf):没有子节点的节点。
- 子树(Subtree):树的某个节点及其所有后代节点构成的树。
- 深度(Height):树的高度是从根节点到最深叶子节点的最长路径上的边数。
- 深度(Depth):节点的深度是从根节点到该节点的路径上的边数。
三、二叉树
二叉树是一种特殊的树结构,每个节点最多有两个子节点,通常称为左子节点和右子节点。二叉树的基本概念包括:
- 节点数:二叉树的节点数可以是任意非负整数。
- 满二叉树(Full Binary Tree):每个节点要么是叶子节点,要么有两个子节点。
- 完全二叉树(Complete Binary Tree):除了最后一层外,所有层的节点都被完全填满,最后一层的节点尽可能靠左。
- 在一棵完全二叉树中,若有 𝑛n 个节点,则叶子节点的数量 𝐿L 可以通过以下公式计算:
𝐿=𝑛+1/2 = L=2n+1
- 非叶子节点数:
- 非叶子节点数 𝐼I 可以通过以下公式计算:𝐼=𝑛−𝐿
满二叉树是指每个节点都有两个子节点的二叉树。对于满二叉树,节点个数与层数之间的关系可以用以下公式表示:
- 节点个数公式:
- 如果满二叉树的层数为 ℎh,则节点个数 𝑛n 的公式为:
𝑛=2ℎ−1n=2h−1
- 其中,层数 ℎh 从 1 开始计数,根节点为第 1 层。
- 层数与节点个数的关系:
- 如果已知节点个数 𝑛n,可以通过以下公式计算出层数 ℎh:
ℎ=log2(𝑛+1)h=log2(n+1)
- 每层的节点个数:
- 在满二叉树中,第 𝑖i 层的节点个数为 2𝑖−12i−1(𝑖i 从 1 开始计数)。
#include <stdlib.h>
#include <stdio.h>
// 定义树节点的数据类型
typedef char TDataType;
// 定义二叉树节点结构体
typedef struct TNode {
TDataType data; // 节点存储的数据
struct TNode *pl; // 指向左子节点的指针
struct TNode *pr; // 指向右子节点的指针
} TNode_t;
// 预定义的树结构,'#' 表示空节点
char tree[] = {"ABEH###G##CF#D##I##"};
int idx = 0; // 用于遍历 tree 数组的索引
// 创建二叉树的函数
TNode_t *create_bin_tree() {
TDataType data = tree[idx++]; // 从 tree 数组中获取当前节点数据
if (data == '#') { // 如果数据是 '#',表示该节点为空
return NULL;
}
// 分配内存给新节点
TNode_t *pnode = malloc(sizeof(TNode_t));
if (NULL == pnode) { // 检查内存分配是否成功
perror("fail malloc");
return NULL;
}
pnode->data = data; // 设置节点数据
pnode->pl = create_bin_tree(); // 递归创建左子树
pnode->pr = create_bin_tree(); // 递归创建右子树
return pnode; // 返回创建的节点
}
// 前序遍历函数
void pre_order(TNode_t *proot) {
if (NULL == proot) { // 如果当前节点为空,返回
return;
}
printf("%c", proot->data); // 访问根节点
pre_order(proot->pl); // 递归遍历左子树
pre_order(proot->pr); // 递归遍历右子树
}
// 中序遍历函数
void mid_order(TNode_t *proot) {
if (NULL == proot) { // 如果当前节点为空,返回
return;
}
mid_order(proot->pl); // 递归遍历左子树
printf("%c", proot->data); // 访问根节点
mid_order(proot->pr); // 递归遍历右子树
}
// 后序遍历函数
void pos_order(TNode_t *proot) {
if (NULL == proot) { // 如果当前节点为空,返回
return;
}
pos_order(proot->pl); // 递归遍历左子树
pos_order(proot->pr); // 递归遍历右子树
printf("%c", proot->data); // 访问根节点
}
// 计算树的节点总数
int get_tree_node_cnt(TNode_t *proot) {
if (NULL == proot) { // 如果当前节点为空,返回 0
return 0;
}
// 递归计算左子树和右子树的节点数,加上当前节点
return get_tree_node_cnt(proot->pl) + get_tree_node_cnt(proot->pr) + 1;
}
// 计算树的层数
int get_tree_layer_cnt(TNode_t *proot) {
if (NULL == proot) { // 如果当前节点为空,返回 0
return 0;
}
// 递归计算左子树和右子树的层数,取较大者加 1
int cntl = get_tree_layer_cnt(proot->pl);
int cntr = get_tree_layer_cnt(proot->pr);
return (cntl > cntr ? cntl : cntr) + 1;
}
// 销毁树的函数,释放节点内存
void destroy_tree(TNode_t *proot) {
if (NULL == proot) { // 如果当前节点为空,返回
return;
}
destroy_tree(proot->pl); // 递归销毁左子树
destroy_tree(proot->pr); // 递归销毁右子树
free(proot); // 释放当前节点的内存
}
// 层序遍历函数(假设队列的实现已定义)
void layer_order(TNode_t *proot) {
// 实现层序遍历的代码,使用队列
}