入门级-数据结构-2、简单树:二叉树的遍历(前序、中序、后序)

入门级-数据结构-2、简单树:二叉树的遍历(前序、中序、后序)

一、基本概念

二叉树:一种特殊的树形数据结构,每个节点最多只有两个子节点,分别称为左子节点和右子节点。

// 二叉树节点的基本结构

typedef struct TreeNode {

int data; // 节点存储的数据

struct TreeNode* left; // 指向左子节点的指针

struct TreeNode* right; // 指向右子节点的指针

} TreeNode;

三种遍历方式的概念

遍历是指按照某种顺序访问树中的每一个节点,且每个节点只访问一次。

  1. 前序遍历(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

  1. 中序遍历(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

  1. 后序遍历(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;
}
相关推荐
地平线开发者3 小时前
J6B vio scenario sample
算法
BothSavage15 小时前
Trae远程开发中DeepSeek自定义模型4054错误的排查与修复
算法
小林ixn15 小时前
从暴力到KMP:一道题彻底搞懂字符串匹配的前世今生
算法
烬羽16 小时前
字符串算法入门:从反转字符串到回文判断,面试不再慌
算法·面试
先吃饱再说1 天前
判断回文字符串,从一行代码到双指针优化
算法
黄敬峰1 天前
深入理解算法核心:从递归思想、数组扁平化到快速排序
算法
得物技术1 天前
从狂野代码到按目标生产:得物推荐 AI Harness 的工程化实践|AICon 演讲整理
人工智能·算法·架构
AI小老六2 天前
SkillOpt 架构拆解:把 Skill 文本当参数,用执行轨迹训练 Agent
后端·算法·ai编程