入门级-数据结构-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;
}
相关推荐
WWW65261 小时前
代码随想录 打卡第五十四天
数据结构·c++·算法
happymaker06261 小时前
LeetCodeHot100——15.三数之和
数据结构·算法
墨白曦煜1 小时前
算法实战笔记:空间换时间的黑魔法——单调栈全景解析(十一)
java·笔记·算法
大模型最新论文1 小时前
小红书提出 RedKnot:分头处理 kv 缓存,延时降低 60%效果还提升
算法
随意起个昵称1 小时前
线性dp-LIS题目6(友好城市,二分优化)
算法·动态规划
数据科学小丫1 小时前
算法:随机森林算法
算法·随机森林·机器学习
Samson Bruce1 小时前
【初高中数学】
线性代数·数学·算法·机器学习
redaijufeng1 小时前
我在C++中深入理解了继承,收获颇丰
java·c++·算法
Ricky05531 小时前
DEIM :采用改进匹配算法实现快速收敛的DETR(中国25年3月研究)
人工智能·算法·目标跟踪