入门级-数据结构-2、简单树:二叉树的遍历(前序、中序、后序)
一、基本概念
二叉树:一种特殊的树形数据结构,每个节点最多只有两个子节点,分别称为左子节点和右子节点。
// 二叉树节点的基本结构
typedef struct TreeNode {
int data; // 节点存储的数据
struct TreeNode* left; // 指向左子节点的指针
struct TreeNode* right; // 指向右子节点的指针
} TreeNode;
三种遍历方式的概念
遍历是指按照某种顺序访问树中的每一个节点,且每个节点只访问一次。
- 前序遍历(Preorder Traversal)
访问顺序:根节点 → 左子树 → 右子树
执行过程:
访问根节点
前序遍历左子树(递归)
前序遍历右子树(递归)
示例:
1 前序遍历结果:1 → 2 → 4 → 5 → 3
/ \
2 3
/ \
4 5
访问顺序:
步骤1: 访问根节点 1
步骤2: 进入左子树(以2为根)→ 访问2
步骤3: 进入2的左子树 → 访问4
步骤4: 返回,进入2的右子树 → 访问5
步骤5: 返回,进入1的右子树 → 访问3
- 中序遍历(Inorder Traversal)
访问顺序:左子树 → 根节点 → 右子树
执行过程:
中序遍历左子树(递归)
访问根节点
中序遍历右子树(递归)
示例:
1 中序遍历结果:4 → 2 → 5 → 1 → 3
/ \
2 3
/ \
4 5
访问顺序:
步骤1: 进入1的左子树(以2为根)
步骤2: 进入2的左子树 → 访问4
步骤3: 返回,访问2
步骤4: 进入2的右子树 → 访问5
步骤5: 返回,访问1
步骤6: 进入1的右子树 → 访问3
- 后序遍历(Postorder Traversal)
访问顺序:左子树 → 右子树 → 根节点
执行过程:
后序遍历左子树(递归)
后序遍历右子树(递归)
访问根节点
示例:
1 后序遍历结果:4 → 5 → 2 → 3 → 1
/ \
2 3
/ \
4 5
访问顺序:
步骤1: 进入1的左子树(以2为根)
步骤2: 进入2的左子树 → 访问4
步骤3: 进入2的右子树 → 访问5
步骤4: 返回,访问2
步骤5: 进入1的右子树 → 访问3
步骤6: 返回,访问1
二、代码实现
首先,我们需要定义二叉树的节点结构
#include <stdio.h>
#include <stdlib.h>
// 二叉树节点结构
typedef struct TreeNode {
int data; // 节点数据
struct TreeNode* left; // 左子树指针
struct TreeNode* right; // 右子树指针
} TreeNode;
// 创建新节点
TreeNode* createNode(int data) {
TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode));
newNode->data = data;
newNode->left = NULL;
newNode->right = NULL;
return newNode;
}
前序遍历(根左右)
// 前序遍历(递归实现)
c
void preorderTraversal(TreeNode* root) {
if (root == NULL) {
return;
}
printf("%d ", root->data); // 访问根节点
preorderTraversal(root->left); // 遍历左子树
preorderTraversal(root->right); // 遍历右子树
}
// 前序遍历(非递归实现,使用栈)
c
void preorderTraversalIterative(TreeNode* root) {
if (root == NULL) return;
TreeNode* stack[100]; // 简单栈实现
int top = -1;
stack[++top] = root;
while (top >= 0) {
TreeNode* node = stack[top--];
printf("%d ", node->data);
// 注意:栈是后进先出,所以先压右子树,再压左子树
if (node->right) {
stack[++top] = node->right;
}
if (node->left) {
stack[++top] = node->left;
}
}
}
中序遍历(左根右)
c
// 中序遍历(递归实现)
void inorderTraversal(TreeNode* root) {
if (root == NULL) {
return;
}
inorderTraversal(root->left); // 遍历左子树
printf("%d ", root->data); // 访问根节点
inorderTraversal(root->right); // 遍历右子树
}
// 中序遍历(非递归实现,使用栈)
c
void inorderTraversalIterative(TreeNode* root) {
if (root == NULL) return;
TreeNode* stack[100];
int top = -1;
TreeNode* current = root;
while (current != NULL || top >= 0) {
// 将左子树的所有节点压入栈
while (current != NULL) {
stack[++top] = current;
current = current->left;
}
// 弹出栈顶节点并访问
current = stack[top--];
printf("%d ", current->data);
// 转向右子树
current = current->right;
}
}
后序遍历(左右根)
c
// 后序遍历(递归实现)
void postorderTraversal(TreeNode* root) {
if (root == NULL) {
return;
}
postorderTraversal(root->left); // 遍历左子树
postorderTraversal(root->right); // 遍历右子树
printf("%d ", root->data); // 访问根节点
}
// 后序遍历(非递归实现,使用两个栈)
c
void postorderTraversalIterative(TreeNode* root) {
if (root == NULL) return;
TreeNode* stack1[100];
TreeNode* stack2[100];
int top1 = -1, top2 = -1;
stack1[++top1] = root;
while (top1 >= 0) {
TreeNode* node = stack1[top1--];
stack2[++top2] = node;
if (node->left) {
stack1[++top1] = node->left;
}
if (node->right) {
stack1[++top1] = node->right;
}
}
// 输出stack2中的节点(逆序)
while (top2 >= 0) {
printf("%d ", stack2[top2--]->data);
}
}
主程序实现
c
int main() {
// 构建示例二叉树:
// 1
// / \
// 2 3
// / \
// 4 5
TreeNode* root = createNode(1);
root->left = createNode(2);
root->right = createNode(3);
root->left->left = createNode(4);
root->left->right = createNode(5);
printf("前序遍历(递归): ");
preorderTraversal(root); // 输出: 1 2 4 5 3
printf("\n");
printf("前序遍历(非递归): ");
preorderTraversalIterative(root); // 输出: 1 2 4 5 3
printf("\n\n");
printf("中序遍历(递归): ");
inorderTraversal(root); // 输出: 4 2 5 1 3
printf("\n");
printf("中序遍历(非递归): ");
inorderTraversalIterative(root); // 输出: 4 2 5 1 3
printf("\n\n");
printf("后序遍历(递归): ");
postorderTraversal(root); // 输出: 4 5 2 3 1
printf("\n");
printf("后序遍历(非递归): ");
postorderTraversalIterative(root); // 输出: 4 5 2 3 1
printf("\n\n");
return 0;
}