引言
递归是程序员的必修课,而链式二叉树正是理解递归的绝佳范例。在这篇文章中,我们将通过实现二叉树的遍历、统计节点、计算深度等操作,真正掌握递归思维。从令人头疼的函数自调用,到游刃有余的递归设计,让我们一起开启这段蜕变之旅。
一、链式二叉树结构定义
1.1 概念
链式结构是指用链表来表示一棵二叉树,即用链表来指示元素的逻辑关系。通常每个节点由三个域组成:数据域和左右指针域,左右指针分别指向该节点左孩子和右孩子所在的地址。
1.2 基本结构(结构上的递归性)
链式二叉树的节点由三部分构成:存储数据的变量、指向左孩子节点的指针、指向右孩子节点的指针。观察节点结构,递归结构就此显现:一个二叉树由根节点、左子树(本身也是一个二叉树)、右子树(本身也是一个二叉树)三部分组成。
这种结构定义是'自相似的',这也进一步证实了链式二叉树的结构是递归性质的。递归的定义是将问题逐步分解为与原始问题相似的更小规模的子问题,直到转化为最简单的子问题。
// 定义链式二叉树的结构--节点结构
typedef int BTDataType;
typedef struct BinaryTreeNode {
BTDataType data; // 存储数据
struct BinaryTreeNode* left; // 指针指向左孩子节点(左子树)
struct BinaryTreeNode* right; // 指针指向右孩子节点(右子树)
} BTNode;
通过这样节点的结构,将所有节点链接在一起形成一棵树。
二、遍历接口实现(操作上的递归性)
链式二叉树的结构是递归的,那么对树进行的大多数操作,其算法必然是递归的。处理整个二叉树和处理它的子树,结构都是相似的,导致使用的是完全相同的方法。
| 二叉树遍历接口 | 描述 | 行为简记 |
|---|---|---|
| 前序遍历 | 先访问当前节点,然后递归遍历左子树,最后递归遍历右子树 | 根 -> 左 -> 右 |
| 中序遍历 | 先递归遍历左子树,然后访问当前节点,最后递归遍历右子树 | 左 -> 根 -> 右 |
| 后序遍历 | 先递归遍历左子树,然后递归遍历右子树,最后访问当前节点 | 左 -> 右 -> 根 |
| 层序遍历 | 按树的深度,从根节点开始,一层一层地依次访问节点 | 从上到下,从左到右 |
2.1 前序遍历(根左右)
前序遍历,又称为先根遍历,其遍历规则为:先遍历根节点,再遍历左子树,最后遍历右子树。简记为'根左右'。
思路:首先判断根节点是否为空,为空直接结束;不为空,先打印根节点数据。遍历完根节点,对左子树进行前序遍历,在函数内再次调用自己,将根节点的左孩子指针传参。前序遍历完左子树,开始对右子树进行前序遍历,再次调用自己,将根节点的右孩子指针传参。
// Tree.c
{
(root == ) {
();
;
}
(, root->data);
PreOrder(root->left);
PreOrder(root->right);
}


