7-1 根据后序和中序遍历输出先序遍历 (PTA-数据结构)

本题要求根据给定的一棵二叉树的后序遍历和中序遍历结果,输出该树的先序遍历结果。

输入格式:

第一行给出正整数N(≤30),是树中结点的个数。随后两行,每行给出N个整数,分别对应后序遍历和中序遍历结果,数字间以空格分隔。题目保证输入正确对应一棵二叉树。

输出格式:

在一行中输出Preorder: 以及该树的先序遍历结果。数字间有1个空格,行末不得有多余空格。

输入样例:

7
2 3 1 5 7 6 4
1 2 3 4 5 6 7

输出样例:

Preorder: 4 1 3 2 6 5 7

通过截图:

 


 思路分析:

        起初看到后序遍历和中序遍历,第一想法是用这个数组创建一棵树,但是考虑到我之前写过的创建树的代码不接受这样的输入(以前的问题),因此开始考虑能不能通过我们人类的思维方式,来想一个能用后序和中序推出先序的算法(相信三者转换是有规律的,因为我们做那种简答题或者选择题,也是按照一定规律推到树,然后写出来的)。

        例如:


       要知道,后序(Post)遍历是LRV,中序(Min)遍历是LVR,先序(Pre)遍历是VLR(V 根节点,L 左子树结点,R 右子树结点)。下面写一下该题的图示:

        其中,我们不难发现, Post的最后一个字符是根节点(Post的最后一个,Pre的第一个),该结点下面的左子树的根节点是第二个我们要输出的,以此类推。

人类手绘创建的树如下:

        我们在手绘树的时候,发现,在中序遍历数组中所找到根节点,左边的是左子树,右边的是右子树,即  (1((2)3))4((5)6(7)) 红色括号为右子树,深绿为左子树,准备好之后,明白我们要找到根(root),子树一个括号中的第一个元素位置(start),子树括号最后一个元素位置(fin)。

        树大概是比较推荐用递归来写,所以我选择了用递归来写,之后疯狂debug折磨自己。因为非递归的思路不是很清楚,我们下面决定用递归来写(之前文章内容就没写过非递归的遍历检查,所以这里行进困难),递归的思路是先序遍历寻找,找到本次操作的根节点后,在中序中寻找此结点,记录下此节点的下标位置,作为在左子树或是右子树的位置线索。

位置线索思考与整理:

        画图表,找到相关联的数字线索,做出数学公式,此处普适公式寻找比较困难,从特例开始(普朗克也是这样发现能量子的),此处思路参考了:已知后序与中序输出前序(先序) – 柳婼 の blog (liuchuo.net)icon-default.png?t=N7T8https://www.liuchuo.net/archives/2090        此思路表格展示为【表头第一列为相对于其父母结点的位置,其后数字个数为所在层数+位置(左子树为1,右子树为2),root,start,fin上面已有赘述,i为root元素在中序遍历中的下标位置,n为此结点的值(最后两行是博主在写时没有列出来的,尤其是start和fin,因此博主有蒙对的嫌疑!!不过后来列表的时候居然完美吻合)】:

         因此,经过观察和统计,整理(Main 0 -> Left 1,Right 1.2 -> Left 1.2.1)左子树的计算公式为 :NextRoot=Root-fin+i ,NextFin = iNextStart=start

        整理(Main 0 -> Right 2,Left 1 ->Right 1.2 )右子树的计算公式为:NextRoot=root-1NextFin=finNextStart=i+i

        这样,我们就明白了整体流程(当然,博主是边想边写的,这块debug了好长时间) ,现在我们要将它写成代码。


 代码整理(递归):

//
// Created by DDD on 2023/11/20.
//
#include <stdio.h>

void makePre(int post[], int min[], int root, int fin, int start){
    if((fin <= start)||(root<0))
        return;
    int i;
    int head = post[root];

    for(i=start; i<fin;i++) {
        if (min[i] == head) {
            break;
        }
    }

    printf(" %d",head);            //此处处理了题目中输出要求
    makePre(post,min,root-fin+i,i,start);    //左子树
    makePre(post,min,root-1,fin,i+1);        //右子树
}

int main(){
    int num;
    scanf("%d",&num);
    int post[num];                      //后序
    int min[num];                       //中序
    for(int i=0; i<num;i++){
        scanf("%d",&post[i]);
    }
    for(int i=0; i<num;i++){
        scanf("%d",&min[i]);
    }
    printf("Preorder:");
    makePre(post,min,num - 1,num,0);
}

return 0;    //归去来

  • 10
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值