OJ题目 P1138 American Heritage 根据二叉树的前序遍历和中序遍历求出二叉树的后序遍历

文章提供了一个C语言程序,该程序使用递归算法根据给定的二叉树前序和中序遍历结果,计算并输出后序遍历序列。主要思路是通过先序遍历找到根节点,在中序遍历中确定左右子树,然后递归处理左右子树。
摘要由CSDN通过智能技术生成

题目描述

给出一棵二叉树的前序遍历 (preorder) 和中序遍历 (inorder),求它的后序遍历 (postorder)。该二叉树的结点的值为大写的26个字母的其中一个,且各个结点的值不重复。

相关知识

前序遍历:先遍历根结点,再遍历左子树和右子树,对左子树和右子树的遍历也遵循根左右的原则

中序遍历:先遍历左子树,再遍历根结点,最后遍历右子树,对于左右子树的遍历也遵循左根右的原则

后序遍历:先遍历左子树,再遍历右子树,最后遍历根结点,对于左右子树的遍历也遵循左右根原则 

如何根据二叉树的先序遍历和中序遍历还原该二叉树的形态

  1. 在先序遍历中找到第一个结点,该节点为该二叉树的根结点
  2. 在中序遍历中找到根结点的位置,则在根结点的左边为左子树的节点元素,在根结点的右边为右子树的元素,继续对左子树和右子树用一样的方法找到左子树和右子树的左子树和右子树。

从上诉方法我们可以很明显的看到求解此题的方法是递归的,所以需要用到递归的算法

解题思路

对于后序遍历而言,我们要先遍历左子树,再遍历右子树,最后遍历根结点,所以递归算法思想是:

  1. 找到该树的左子树
  2. 找到该树的右子树
  3. 输出根结点的值 

对该树的左子树和右子树继续调用本方法,直到该树的左子树和右子树均为空 时即到达叶子节点时,输出该节点的元素的值即可得到后序遍历的结果

程序源代码以及运行结果如下,再题目的源代码中给出了完整的注释,即思考过程

程序源代码:

//给定二叉树的前序遍历和中序遍历求出树的后序遍历,

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>		          //该头文件包含了malloc函数的声明;
#include<string.h>
#define N 26            //二叉树的节点个数不确定,确定的是,每一个结点元素的值都是大写的26个英文字母中的其中一个,且不会有重复,所以显然该二叉树的结点不会超过26个

//给定二叉树的先序遍历和中序遍历,求其后序遍历结果,需要用到递归的思想,其求解步骤有很明显的递归思想


//设计一个函数,该函数的功能是找到一个字符数组中数组元素值为c的元素的数组下标,并作为函数值来返回;
int find_index(char *p,char c)
{
	for (int i = 0;p[i] != '\0'; i++)
	{
		if (p[i] == c)
			return i;
	}
}


void Solve_Result_Post_Order(char *pre, char *middle)             
{
	char ltree_pre[N],rtree_pre[N],ltree_middle[N],rtree_middle[N];            //分别找到左子树,和右子树以及他们的前序遍历和后序遍历

	if (strlen(pre)==0 || strlen(middle)==0)                   //若子树为空则返回
	{
		return;
	}
	
	
	
	
	int flag = find_index(middle,pre[0]),count,lmark=1,rmark=0;           //找到中序遍历中根结点的位置,lmark用于辅助寻找左子树的先序遍历
	count = flag + 1;
	
	
	
	
	//分别找到左子树和右子树的中序遍历



	
	
	//找到左子树的中序遍历
	for (int i = 0; i < flag; i++)
	{
		ltree_middle[i] = middle[i];
	}
	ltree_middle[flag] = '\0';             //注意为其添加字符串结束标识符
	
	
	
	
	//找到左子树的前序遍历

	for (int i = 0; i < flag; i++)
	{
		ltree_pre[i] = pre[lmark];
		lmark++;
	}
	ltree_pre[lmark] = '\0';

	
	
	//找右子树的中序遍历
	for (int i = count; middle[i] != '\0'; i++)
	{
		rtree_middle[rmark] = middle[i];
		rmark++;
	}
	rtree_middle[rmark] = '\0';
	
	
	
	//找到右子树的先序遍历
	int assist = 0;
	for (int i = count; pre[i] != '\0'; i++)
	{
		rtree_pre[assist] = pre[i];
		assist++;
	}
	rtree_pre[assist] = '\0';

	
	
	
	//先对左子树进行递归调用本函数,再对右子树递归调用本函数,最后打印本结点的值

	Solve_Result_Post_Order(ltree_pre, ltree_middle);
	Solve_Result_Post_Order(rtree_pre, rtree_middle);
	printf("%c", pre[0]);

				
}




int main()
{

	char PreOrder[N];
	char MiddleOrder[N];
	while (scanf("%s",MiddleOrder) != EOF)
	{
		scanf("%s",PreOrder);
		Solve_Result_Post_Order(PreOrder, MiddleOrder);
		printf("\n");
	}
	return 0;
}

运行结果截图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值