先序遍历,中序遍历,后序遍历的相互求法(C语言版)

        今天来写一下先序遍历,中序遍历和后序遍历的相互求法。

        首先我们要知道先序遍历,中序遍历和后序遍历各自遍历的顺序:
        1.先序遍历(根左右的顺序):①访问根节点
                                                          ②先序遍历左子树
                                                          ③先序遍历右子树
        2.中序遍历(左根右的顺序):①中序遍历左子树
                                                          ②访问根节点
                                                          ③中序遍历右子树
        3.中序遍历(左右根的顺序):①后序遍历左子树
                                                          ②后序遍历右子树
                                                          ③访问根节点

        我们要知道,根据先序遍历和后序遍历无法唯一确定一棵二叉树,所以无法根据先序遍历和后序遍历输出中序遍历。这是因为先序和后序遍历不能确定根节点的具体位置。例如,考虑两棵形状不同但具有相同先序和后序遍历的树:

   A           A
  /             \
 B               B

        这两棵树的先序遍历都是AB,后序遍历都是BA,但它们的中序遍历分别是BA和AB,所以我们不能仅根据先序和后序遍历来确定中序遍历。

        然而,如果我们知道这棵树的叶子节点或者所有的内部节点都有两个子节点(即满二叉树),那么我们可以使用先序和后序遍历来重建这棵树。但在一般情况下,我们需要中序遍历与先序或后序遍历配合才能唯一确定一棵二叉树。所以在这里我们只进行用中序遍历和后序遍历求先序遍历以及用先序遍历和中序遍历求后序遍历的讨论。

一、已知中序遍历和后序遍历,求先序遍历

        例:
        中序遍历:4, 2, 5, 1, 3
        后序遍历:4, 5, 2, 3, 1 

        首先要知道,在后序遍历中,最后一个元素总是根节点。所以在这个例子中,1就是根节点。

        然后,在中序遍历结果中找到 1,它将中序遍历结果分为两部分:左子树的中序遍历结果4, 2, 5和右子树的中序遍历结果 3。

        接下来,需要确定左子树和右子树的后序遍历结果。在后序遍历中,左子树的元素总是在右子树元素的前面。所以在这个例子中,左子树的后序遍历结果是 4, 5, 2,右子树的后序遍历结果是 3。

        现在,可以递归地对左子树和右子树进行相同的操作。对于左子树,可以看到2是根节点,4是左子节点,5是右子节点。对于右子树,3就是一个叶节点。

        所以,这个二叉树的先序遍历结果就是:1(根节点),2(左子树的根节点),4(左子树的左子节点),5(左子树的右子节点),3(右子节点)。

        可以画出该二叉树:
        

        所以,由先序遍历的规则,可以得到先序遍历的顺序为:1,2,4,5,3
        代码如下

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 定义二叉树节点结构体
typedef struct Node {
    int data; // 数据域
    struct Node *left; // 左指针域
    struct Node *right; // 右指针域
} Node;

// 根据后序遍历和中序遍历构建二叉树,并返回根节点指针
Node *buildTree(int *postOrder, int *inOrder, int len) {
    // 如果输入为空或长度为零,返回空指针
    if (postOrder == NULL || inOrder == NULL || len <= 0) {
        return NULL;
    }
    // 创建一个新的节点,将后序遍历的最后一个元素赋值给它的数据域
    Node *root = (Node *)malloc(sizeof(Node));
    root->data = postOrder[len - 1];
    // 在中序遍历中找到根节点的位置
    int pos = 0;
    while (inOrder[pos] != root->data) {
        pos++;
    }
    // 递归地调用函数,分别传入后序遍历和中序遍历的左子树部分和右子树部分
    root->left = buildTree(postOrder, inOrder, pos);
    root->right = buildTree(postOrder + pos, inOrder + pos + 1, len - pos - 1);
    // 返回根节点指针
    return root;
}

// 先序遍历打印二叉树
void preOrder(Node *root) {
    // 如果节点为空,返回
    if (root == NULL) {
        return;
    }
    // 打印当前节点的数据域
    printf("%d ", root->data);
    // 先序遍历左子树
    preOrder(root->left);
    // 先序遍历右子树
    preOrder(root->right);
}

// 测试代码
int main() {
    // 定义后序遍历和中序遍历的整数数组
    int postOrder[] = {4, 5, 2, 3, 1};
    int inOrder[] = {4, 2, 5, 1, 3};
    // 构建二叉树,并得到根节点指针
    Node *root = buildTree(postOrder, inOrder, sizeof(postOrder) / sizeof(int));
    // 先序遍历打印二叉树
    printf("先序遍历结果为:\n");
    preOrder(root);
    printf("\n");
    // 释放内存
    free(root);
    return 0;
}

运行结果如下
先序遍历结果为:
1 2 4 5 3

二、已知先序遍历和中序遍历,求后序遍历

         例:
        先序遍历:1, 2, 4, 5, 3
        中序遍历:4, 2, 5, 1, 3

        首先要知道,在先序遍历中,第一个元素总是根节点。所以在这个例子中,1就是根节点。

        然后,在中序遍历结果中找到 1,它将中序遍历结果分为两部分:左子树的中序遍历结果 4, 2, 5和右子树的中序遍历结果 3。

        接下来,需要确定左子树和右子树的先序遍历结果。在先序遍历中,左子树的元素总是在右子树元素的前面。所以在这个例子中,左子树的先序遍历结果是 2, 4, 5 ,右子树的先序遍历结果是 3 。

        现在,可以递归地对左子树和右子树进行相同的操作。对于左子树,可以看到2是根节点,4是左子节点,5是右子节点。对于右子树,3就是一个叶节点。

        所以,这个二叉树的后序遍历结果就是:4(左子树的左子节点),5(左子树的右子节点),2(左子树的根节点),3(右子节点),1(根节点)。

        可以画出该二叉树:

        所以,由后序遍历的规则,可以得到后序遍历的顺序为:4,5,2,3,1
        代码如下

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 定义二叉树节点结构体
typedef struct Node {
    int data; // 数据域
    struct Node *left; // 左指针域
    struct Node *right; // 右指针域
} Node;

// 根据先序遍历和中序遍历构建二叉树,并返回根节点指针
Node *buildTree(int *preOrder, int *inOrder, int len) {
    // 如果输入为空或长度为零,返回空指针
    if (preOrder == NULL || inOrder == NULL || len <= 0) {
        return NULL;
    }
    // 创建一个新的节点,将先序遍历的第一个元素赋值给它的数据域
    Node *root = (Node *)malloc(sizeof(Node));
    root->data = preOrder[0];
    // 在中序遍历中找到根节点的位置
    int pos = 0;
    while (inOrder[pos] != root->data) {
        pos++;
    }
    // 递归地调用函数,分别传入先序遍历和中序遍历的左子树部分和右子树部分
    root->left = buildTree(preOrder + 1, inOrder, pos);
    root->right = buildTree(preOrder + pos + 1, inOrder + pos + 1, len - pos - 1);
    // 返回根节点指针
    return root;
}

// 后序遍历打印二叉树
void postOrder(Node *root) {
    // 如果节点为空,返回
    if (root == NULL) {
        return;
    }
    // 后序遍历左子树
    postOrder(root->left);
    // 后序遍历右子树
    postOrder(root->right);
    // 打印当前节点的数据域
    printf("%d ", root->data);
}

// 测试代码
int main() {
    // 定义先序遍历和中序遍历的整数数组
    int preOrder[] = {1, 2, 4, 5, 3};
    int inOrder[] = {4, 2, 5, 1, 3};
    // 构建二叉树,并得到根节点指针
    Node *root = buildTree(preOrder, inOrder, sizeof(preOrder) / sizeof(int));
    // 后序遍历打印二叉树
    printf("后序遍历结果为:\n");
    postOrder(root);
    printf("\n");
    // 释放内存
    free(root);
    return 0;
}

运行结果如下
后序遍历结果为:
4 5 2 3 1

这就是我对已知中序遍历和后序遍历求先序遍历与已知先序遍历和中序遍历求后序遍历的理解,欢迎大家指出我的错误,以便我后续进行改正。

  • 31
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 先序遍历中序遍历后序遍历都是二叉树遍历的方法,它们的区别在于访问根节点的顺序和访问左右子树的顺序不同。 1. 先序遍历 先序遍历的访问顺序是:根节点 -> 左子树 -> 右子树。 例如,对于下面这棵二叉树: ``` 1 / \ 2 3 / \ / \ 4 5 6 7 ``` 其先序遍历序列为:1 2 4 5 3 6 7。 2. 中序遍历 中序遍历的访问顺序是:左子树 -> 根节点 -> 右子树。 例如,对于下面这棵二叉树: ``` 1 / \ 2 3 / \ / \ 4 5 6 7 ``` 其中序遍历序列为:4 2 5 1 6 3 7。 3. 后序遍历 后序遍历的访问顺序是:左子树 -> 右子树 -> 根节点。 例如,对于下面这棵二叉树: ``` 1 / \ 2 3 / \ / \ 4 5 6 7 ``` 其后序遍历序列为:4 5 2 6 7 3 1。 希望这个回答能够解决您的疑惑。 ### 回答2: 先序遍历中序遍历后序遍历是二叉树的三种常见遍历方式。 先序遍历:先访问根节点,然后遍历左子树,最后遍历右子树。在遍历的过程中,根节点总是在左子树和右子树之前被访问到。 中序遍历:先遍历左子树,然后访问根节点,最后遍历右子树。在遍历的过程中,根节点总是在左子树和右子树之间被访问到。 后序遍历:先遍历左子树,然后遍历右子树,最后访问根节点。在遍历的过程中,根节点总是在左子树和右子树之后被访问到。 以一个简单的二叉树为例,如下所示: A / \ B C / \ \ D E F 先序遍历:A -> B -> D -> E -> C -> F 中序遍历:D -> B -> E -> A -> C -> F 后序遍历:D -> E -> B -> F -> C -> A 其中,先序遍历的访问顺序是根节点->左子树->右子树,中序遍历的访问顺序是左子树->根节点->右子树,后序遍历的访问顺序是左子树->右子树->根节点。 这三种遍历方式都有自己的应用场景。先序遍历常用于打印表达式,中序遍历常用于二叉搜索树的中序输出,后序遍历常用于计算二叉树的表达式。 总之,先序遍历中序遍历后序遍历是对二叉树的不同遍历顺序,每种遍历方式都有自己的特点和应用场景。 ### 回答3: 先序遍历中序遍历后序遍历都是二叉树遍历的方法。下面分别对这三种遍历进行简单的说明。 先序遍历是指从根节点开始,先遍历根节点,然后按照先序遍历的顺序,递归遍历左子树和右子树。具体步骤如下:先输出根节点,然后递归遍历左子树,最后递归遍历右子树。 中序遍历是指从根节点开始,先递归遍历左子树,然后输出根节点,最后再递归遍历右子树。具体步骤如下:先递归遍历左子树,然后输出根节点,最后递归遍历右子树。 后序遍历是指从根节点开始,先递归遍历左子树,然后递归遍历右子树,最后输出根节点。具体步骤如下:先递归遍历左子树,然后递归遍历右子树,最后输出根节点。 这三种遍历方法都是通过递归的方式实现的,其中先序遍历中序遍历的次序不同,而后序遍历的次序更为靠后。不同的遍历方式可以帮助我们了解二叉树结构的不同特点,如先序遍历可以轻松找到二叉树的根节点,中序遍历可以输出二叉树的有序节点序列,后序遍历可以方便地进行二叉树的删除操作。 总结起来,先序遍历中序遍历后序遍历都是二叉树遍历的方法,只不过它们的递归次序不同。熟练掌握这三种遍历方式可以帮助我们更好地理解二叉树的结构和特点。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值