已知二叉树的先序和中序求后序和已知中序和后序求前序

本文详细介绍了如何使用先序、中序和后序遍历序列来求解二叉树的序列,包括先序与中序求后序及中序与后序求先序的过程,并提供了相应的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先介绍树的三种遍历方式的遍历顺序:

先序遍历:根、左子树、右子树(特点:第一个元素为根)

中序遍历:左子树、根、右子树(特点:根的两边分别为左子树和右子树)

后序遍历:左子树、右子树、根(特点:最后一个元素为根)

有如下图的二叉树:

其先序、中序、后序遍历分别为:DBACEGF、ABCDEGF、ACBFGED。

1、已知先序和中序求后序

先序遍历的第一个字符为根,因此只需在中序遍历中找到它,就可以把根节点的左子树和右子树分开,就可以知道左子树的字符个数和右子树的字符个数,然后可以确定先序遍历中哪部分是左子树,哪部分是右子树,之后递归先序遍历的序列,直到结束。

如上面的例子:先序遍历的第一个字符是D,则根节点为D,从中序遍历中可以找到D的位置,左边的ABC即为左子树的字符,右边的EGF即为右子树的字符,如果开始递归函数为:build("DBACEGF"),则找到根的位置后,可以分为递归左子树的先序遍历和递归右子树的先序遍历:build("BAC")和build("EGF"),其对应的中序遍历为:ABC和EGF。然后继续进行以上步骤,直到找完先序序列。每找到根就可以直接输出或保存到数组中,需要注意的是递归的时候不要把根包含在内。

代码如下:

//已知先序和中序求后序
#include<stdio.h>
#include <cstring>
char a[27],b[27];//存先序遍历和中序遍历
void fun(int ab, int ae, int bb, int be)
{//四个参数分别为:先序遍历的起始位置和结束位置和中序遍历的起始位置和结束位置
    int i;
    if(ab>ae)//如果已经到达叶子,返回
        return;
    for(i=bb; b[i]!=a[ab]; ++i);//找到根节点在中序遍历中的位置
    fun(ab+1, ae-be+i, bb, i-1);//递归求左子树的后序遍历,ab+1是指把根去掉之后的位置
    fun(ae-be+i+1, ae, i+1, be);//递归求右子树的后序遍历
    putchar(a[ab]);//在递归结束后输出根
}
int main()
{
    int i;
    while(scanf("%s%s", a, b) != EOF)
    {
        int len = strlen(a);
        fun(0, len-1, 0, len-1);
        puts("");
    }
}
其中ae-be+i是ae-(be-i),be-i是右子树的长度,ae-(be-i)即是先序遍历中左子树的结束位置,递归右子树同理。

2、已知中序和后序求先序

后序序列的特点是最后一个是根,道理与已知先序和中序求后序一样,同样是递归,只是需要改变几个参数。附上代码和注释。

//已知中序序列和后序序列,求先序序列
#include<stdio.h>
#include <cstring>
char a[27],b[27];
void fun(int ab, int ae, int bb, int be)
{
    int i;
    if(ab>ae)
        return;
    putchar(a[ae]);//由于是求先序遍历,所以要先输出根节点
    for(i=bb; b[i]!=a[ae]; ++i);//对应的,后序序列的最后一个为根,所以根为a[ae]
    fun(ab, ae-be+i-1, bb, i-1);//递归求左子树的先序遍历
    fun(ae-be+i, ae-1, i+1, be);//递归求右子树的先序遍历,ae-1为去掉根后的位置
}
int main()
{
    int i;
    while(scanf("%s%s", a, b) != EOF)
    {
        int len = strlen(a);
        fun(0, len-1, 0, len-1);
        puts("");
    }
}
在以上程序中,给函数传递了四个参数,分别代表起始和结束位置,其实可以只需要三个参数即可,因为中序遍历的起始位置可以通过另外一个序列的长度来找到,所以只需要ab、ae、be即可。为了方便理解,我传了四个参数。

已知一棵二叉树前序遍历(Preorder)遍历(Inorder),可以推断出它的后序遍历(Postorder)。这是因为前序、中后序遍历分别对应了“根-左-右”、“左-根-右”“左-右-根”的顺。 下面是一个简单的算法来实现这个转换: 1. **前序遍历**给出的是根节点 -> 左子 -> 右子的顺。 2. **中遍历**给出的是左子 -> 根节点 -> 右子的顺。 3. 后序遍历需要将这两个信息组合起来找到根节点的位置。 首,我们需要从前序遍历中找到根节点。这在前序遍历中是最出现的元素,因为它代表开始。一旦找到根,我们可以在中遍历中确定左右子的位置,因为左子的节点会出现在根之前,而右子的节点会出现在根之后。 以下是一个伪代码实现: ```c void getPostorder(int* preorder, int* inorder, int start, int end) { if (start > end) return; // 在中遍历中找根节点的位置 int rootIndex = -1; for (int i = start; i <= end; ++i) { if (inorder[i] == preorder[start]) { rootIndex = i; break; } } // 后续处理 int leftEnd = rootIndex - 1; // 在中中根左边的部分结束位置 int rightStart = rootIndex + 1; // 在中中根右边的部分开始位置 // 递归处理左子右子 getPostorder(preorder, inorder, start, leftEnd); getPostorder(preorder, inorder, rightStart, end); // 将根节点添加到结果后 printf("%d ", preorder[start]); } // 调用函数并传入数据 int preorder[] = {1, 2, 4, 5, 3}; int inorder[] = {4, 2, 5, 1, 3}; int n = sizeof(preorder)/sizeof(preorder[0]); getPostorder(preorder, inorder, 0, n-1); ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值