1. 二叉树链式结构实现基础
在数据结构领域,二叉树是一种非常重要的非线性数据结构。与线性表、栈、队列等线性结构不同,二叉树采用分层存储的方式,每个节点最多有两个子节点,分别称为左子节点和右子节点。这种结构在计算机科学中有着广泛的应用,比如文件系统的目录结构、数据库索引、编译器语法分析等场景。
1.1 二叉树节点定义
我们先来看二叉树节点的基本结构定义。在C语言中,通常使用结构体来表示二叉树节点:
c复制typedef char BTDataType;
typedef struct BinaryTreeNode {
BTDataType data; // 节点存储的数据
struct BinaryTreeNode* left; // 左子节点指针
struct BinaryTreeNode* right; // 右子节点指针
} BTNode;
这个结构体定义了几个关键元素:
data字段用于存储节点的实际数据,这里我们定义为char类型left和right指针分别指向当前节点的左子树和右子树- 使用
typedef为结构体创建了别名BTNode,简化后续代码书写
1.2 节点创建函数
为了简化节点的创建过程,我们可以编写一个专门的函数来初始化新节点:
c复制BTNode* BuyNode(BTDataType x) {
BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));
if (newnode == NULL) {
perror("malloc fail");
exit(1);
}
newnode->data = x;
newnode->left = NULL;
newnode->right = NULL;
return newnode;
}
这个函数完成了以下几个工作:
- 使用
malloc动态分配内存空间 - 检查内存分配是否成功
- 初始化节点的数据和子节点指针
- 返回新创建的节点指针
注意:在实际项目中,应该考虑添加错误处理机制,比如当内存分配失败时,可以选择返回NULL而不是直接退出程序,让调用者决定如何处理这种情况。
1.3 手动构建二叉树示例
为了便于学习和测试,我们可以手动构建一个简单的二叉树:
c复制BTNode* CreateBinaryTree() {
BTNode* nodeA = BuyNode('A');
BTNode* nodeB = BuyNode('B');
BTNode* nodeC = BuyNode('C');
// 其他节点创建...
// 构建节点关系
nodeA->left = nodeB;
nodeA->right = nodeC;
// 其他关系构建...
return nodeA; // 返回根节点
}
这种手动构建方式虽然简单直接,但并不适合实际应用场景。在实际开发中,我们通常会根据特定规则(如前序遍历序列)来自动构建二叉树。手动构建主要用于教学和测试目的,帮助我们理解二叉树的结构和操作。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 二叉树基本属性计算
理解并实现二叉树基本属性的计算是掌握二叉树操作的基础。这些属性包括节点数量、叶子节点数量、树的高度等,它们都是通过递归算法实现的。
2.1 计算二叉树节点总数
计算二叉树节点总数的思路很简单:树的总节点数 = 左子树节点数 + 右子树节点数 + 1(当前节点)。这是一个典型的递归问题。
c复制int BinaryTreeSize(BTNode* root) {
if (root == NULL) {
return 0;
}
return BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
}
递归过程分析:
- 基线条件:如果当前节点为NULL,返回0
- 递归条件:计算左子树节点数 + 右子树节点数 + 当前节点
- 递归会一直深入到叶子节点,然后逐层返回计算结果
时间复杂度分析:每个节点都会被访问一次,所以时间复杂度是O(n),其中n是节点总数。
2.2 计算叶子节点数量
叶子节点是指没有子节点的节点。计算叶子节点数量的方法与计算总节点数类似,但判断条件有所不同。
c复制int BinaryTreeLeafSize(BTNode* root) {
if (root == NULL) {
return 0;
}
if (root->left == NULL && root->right == NULL) {
return 1;
}
return BinaryTreeLeafSize(root->left) + BinaryTre
