048. 使用递归进行树的遍历

在C语言中,递归是实现树遍历的常用方法。树的遍历主要有三种方式:前序遍历中序遍历后序遍历。这些遍历方式通过递归调用实现,能够有效地访问树中的每个节点。

树的结构定义

首先,我们需要定义一个二叉树节点的结构。假设每个节点包含一个整数值和两个指向其左右子节点的指针。

#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));
    if (newNode == NULL) {
        printf("内存分配失败!\n");
        exit(1);
    }
    newNode->data = data;
    newNode->left = NULL;
    newNode->right = NULL;
    return newNode;
}

// 创建一个简单的二叉树
TreeNode* createTree() {
    TreeNode* root = createNode(1);
    root->left = createNode(2);
    root->right = createNode(3);
    root->left->left = createNode(4);
    root->left->right = createNode(5);
    root->right->left = createNode(6);
    root->right->right = createNode(7);
    return root;
}

递归实现树的遍历

前序遍历(Pre-order Traversal)

前序遍历的顺序是:根节点 -> 左子树 -> 右子树

void preOrderTraversal(TreeNode* root) {
    if (root == NULL) {
        return; // 递归终止条件
    }
    printf("%d ", root->data); // 访问根节点
    preOrderTraversal(root->left); // 递归遍历左子树
    preOrderTraversal(root->right); // 递归遍历右子树
}

中序遍历(In-order Traversal)

中序遍历的顺序是:左子树 -> 根节点 -> 右子树

void inOrderTraversal(TreeNode* root) {
    if (root == NULL) {
        return; // 递归终止条件
    }
    inOrderTraversal(root->left); // 递归遍历左子树
    printf("%d ", root->data); // 访问根节点
    inOrderTraversal(root->right); // 递归遍历右子树
}

后序遍历(Post-order Traversal)

后序遍历的顺序是:左子树 -> 右子树 -> 根节点

void postOrderTraversal(TreeNode* root) {
    if (root == NULL) {
        return; // 递归终止条件
    }
    postOrderTraversal(root->left); // 递归遍历左子树
    postOrderTraversal(root->right); // 递归遍历右子树
    printf("%d ", root->data); // 访问根节点
}

主函数

在主函数中,创建一棵树并调用不同的遍历函数。

int main() {
    // 创建一棵简单的二叉树
    TreeNode* root = createTree();

    printf("前序遍历结果:\n");
    preOrderTraversal(root);
    printf("\n");

    printf("中序遍历结果:\n");
    inOrderTraversal(root);
    printf("\n");

    printf("后序遍历结果:\n");
    postOrderTraversal(root);
    printf("\n");

    // 释放树的内存(递归释放)
    void freeTree(TreeNode* node) {
        if (node == NULL) {
            return;
        }
        freeTree(node->left);
        freeTree(node->right);
        free(node);
    }
    freeTree(root);

    return 0;
}

示例运行

假设我们创建的二叉树如下:

        1
       / \
      2   3
     / \ / \
    4  5 6  7

输出结果:

前序遍历结果:
1 2 4 5 3 6 7

中序遍历结果:
4 2 5 1 6 3 7

后序遍历结果:
4 5 2 6 7 3 1

递归遍历的特点

  1. 简洁性:递归实现的代码简洁易读,逻辑清晰。
  2. 效率:递归遍历的时间复杂度为 O(n),其中 n 是树中节点的数量。
  3. 空间复杂度:递归调用会占用系统栈空间,空间复杂度为 O(h),其中 h 是树的高度。
  4. 适用性:递归是实现树遍历的自然方式,适合处理树结构。

通过递归实现树的遍历,可以方便地访问树中的每个节点,适用于各种树相关的算法和数据处理任务。

视频讲解

BiliBili: 视睿网络-哔哩哔哩视频 (bilibili.com)