树的前序遍历、中序遍历、后序遍历相互求解

最近开始着手学习数据结构了,学习的平台是PTA的数据结构,里面学到了树的部分,比较基础也比较重要,所以在这里记录一下,顺便用于以后复习。

一、前序、中序遍历求后序遍历

在这里插入图片描述

输入

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

输出

3 4 2 6 5 1
way1

解题思想:

前序遍历中,根节点一定是会出现在最前面,我们就可以通过这个点来得到每个子树的根节点;

中序遍历中,一个根节点的左右子树肯定是在根节点的左边和右边,那我们是可以通过这个点来快速得到一棵树的左右子树。

那对于一棵子树,我们可以通过每个节点前序遍历中的位置快速得到其根节点,然后再通过中序遍历,得到其左子树和右子树,这样我们就能更进一步进行后面的遍历了。

存入前序遍历和前序遍历中每个数对应的位置

存入中序遍历的数

伪代码

void solve(引入所求范围l,r)

if(范围中只有一个数): 存入后序

for循环找出中序范围内前序遍历数最靠前的,这个数是这个子树的根节点

判断左右的子树继续递归

把这个根节点存入last后序遍历中

#include<iostream>
#include<string>
#include<stack>
using namespace std;
const int maxn=105;
int pre[maxn],in[maxn],last[maxn],position[maxn];
int n,cnt=0; 
void solve(int l,int r)
{
	if(l==r)
	{
		last[++cnt]=in[l];
		return;
	}
	int xh=1e5,wz;
	for(int i=l;i<=r;i++)
	{
		if(position[in[i]]<xh)
		{
			xh=position[in[i]];
			wz=i;
		}
	}
	if(wz-1>=l) solve(l,wz-1);
	if(wz+1<=r) solve(wz+1,r);
	last[++cnt]=in[wz];
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
    	cin>>pre[i];
    	position[pre[i]]=i;
	}
	for(int i=1;i<=n;i++)
	{
		cin>>in[i];
	}
	solve(1,n);
	for(int i=1;i<=n;i++)
	{
		printf("%d ",last[i]);
	}
}
way2

先把前序存入pre,中序存入in

  • solve中的形参
  • prel 当前子树的根节点位置
  • inl当前中序的起始位置
  • lastl当前后序的起始位置

如果n==1,说明这个点是叶节点,直接存入**last[lastl]**处即可

#include<iostream>
#include<string>
#include<stack>
using namespace std;
const int maxn=105;
int pre[maxn],in[maxn],last[maxn],n,cnt=0; 
//参数:PreL为当前前序序列的起始位置,即根节点位置
//InL为当前中序序列中的左或右子树的起始位置
//LastL为后序序列中子序列起始位置的下标
//n为当前左或右子树的长度
void solve(int prel,int inl,int lastl,int n)
{
	if(n==0) return;
	if(n==1) 
	{
		last[lastl]=pre[prel];
		return;
	}
	int root=pre[prel];//当前这棵树的根节点位置
	last[lastl+n-1]=root;//起始位置+总长-1就是最后的位置
	int i;
	for(i=1;i<=n;i++)
	{
		if(in[inl+i]==root)
		break;
	}
	int l=i,r=n-i-1;
	solve(prel+1,inl,lastl,l);
	solve(prel+l+1,inl+l+1,lastl+l,r);
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
    	cin>>pre[i];
	}
	for(int i=1;i<=n;i++)
	{
		cin>>in[i];
	}
	solve(1,1,1,n);
	for(int i=1;i<=n;i++)
	{
		printf("%d ",last[i]);
	}
}

此方法推荐博客
03-树3 Tree Traversals Again (25 分)(前中序变后序)

二、中序、后序遍历求前序遍历

输入

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

输出

1 2 3 4 5 6
way1

与前序中序求后序的way2差不多

#include<iostream>
#include<string>
#include<stack>
using namespace std;
const int maxn=105;
int pre[maxn],in[maxn],last[maxn],position[maxn],n,cnt=0; 
void solve(int l,int r)
{
	if(l==r)
	{
		pre[++cnt]=in[l];
		return;
	}
	int xh=0,wz;
	for(int i=l;i<=r;i++)
	{
		if(position[in[i]]>xh)
		{
			xh=position[in[i]];
			wz=i;
		}
	}
	pre[++cnt]=in[wz];
	if(wz-1>=l) solve(l,wz-1);
	if(wz+1<=r) solve(wz+1,r);
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
    	cin>>in[i];
	}
	for(int i=1;i<=n;i++)
	{
		cin>>last[i];
		position[last[i]]=i;
	}
	solve(1,n);
	for(int i=1;i<=n;i++)
	{
		printf("%d ",pre[i]);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值