根据前序遍历和中序遍历找后续遍历、层次遍历

中序+前序 ——> 后序

法一:将数组传参

由中序遍历和前序遍历得到后续遍历(镜像翻转或不翻转)
这是之前的老做法,把数组作为参数,每次传具体某一段数组的首地址
麻烦的地方在于,有时候找不准某段数组的首地址
以下标0开始的数组,str【i】为首的数组段,地址是str+i
以下标1开始的数组,str【i】为首的数组段,地址也是str+i,不要搞错了,从下标1开始存储,str【i】的地址也是不变的

#include <bits/stdc++.h>
using namespace std;
const int N=35;
vector<int> v;
void print(int in[],int pre[],int len){
	if(len==0)return ;
	int ch=pre[0];
	int i;
	for(i=0;i<len;i++){//0 1 2 3 4
		if(in[i]==ch)break;
	}//in[0]~in[i-1]左,in[i]中,in[i+1]-in[len-1]右
//	print(in,pre+1,i);//左  
	print(in+i+1,pre+i+1,len-i-1);//右 //不进行镜像翻转是2315764
	print(in,pre+1,i);//左   镜像翻转是7 5 6 2 3 1 4
	cout<<ch<<" ";
}
signed main(){//45
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n;
	cin>>n;
	int in[N];
	int pre[N];
	for(int i=0;i<n;i++){
		cin>>in[i];
	}
	for(int i=0;i<n;i++){
		cin>>pre[i];
	}
	print(in,pre,n);

	return 0;
} 

 

法二:将中序下标传参,前序的root传参(前序遍历中总能找到 根节点、左子树根节点、右子树根节点)

异曲同工,可以将传地址改为传递下标,每次只需要根据下标确定左、右子树所在的数组段,通过比较下标边界也可以作为递归出口,原来是根据数字段长度

#include <bits/stdc++.h>
using namespace std;
const int N=35;

	int in[N];//左中右 
	int pre[N];//中左右 
void print(int l,int r,int root){
	if(l>r)return ;
	int ch=pre[root];
	int i;
	for(i=l;i<=r;i++){
		if(in[i]==ch)break;
	}//in 左l~i-1 中i 右 i+1 ~r ,
//	从而得到左长度 i-l 右长度r-i,从而得到in数组左右段 
	print(l,i-1,root+1);//左
	print(i+1,r,root+i-l+1);//右  左+中长度是i-l+1,pre右子树第一个节点是root+i-l+1-1 +1,也就是右子树的根节点 
	cout<<ch<<" ";
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n;
	cin>>n;

	for(int i=0;i<n;i++){
		cin>>in[i];
	}
	for(int i=0;i<n;i++){
		cin>>pre[i];
	}
	print(0,n-1,0);//in数组的下标范围,从而确定左右子树所在的数组段 
//注意,要加上root参数,方能发挥pre数组寻找根节点的作用
//曾记否,当时把数组当作参数,是pre数组和in数组的下标都要重新确定的
//所以print(0,n-1),只传in数组的下标变化是不够的 
	return 0;
} 

 

中序+前序 ——> 层次遍历

这里的level数组可以用map容器代替,否则节点数一多,序号的上限非常大,是2的N次幂,还要初始化为-1
不如用map容器,没有的就相当于上面初始化为-1的

#include <bits/stdc++.h>
using namespace std;
const int N=35;

int in[N];//左中右 
int pre[N];//中左右 
int level[300000];

void print(int l,int r,int root,int index){
	if(l>r)return ;
	int ch=pre[root];
	int i;
	for(i=l;i<=r;i++){
		if(in[i]==ch)break;
	}//in 左l~i-1 中i 右 i+1 ~r ,
//	从而得到左长度 i-l 右长度r-i,从而得到in数组左右段
	level[index]=ch; 

	print(i+1,r,root+i-l+1,index*2+1);
	//右  左+中长度是i-l+1,pre右子树第一个节点是root+i-l+1-1 +1,也就是右子树的根节点 
	print(l,i-1,root+1,index*2+2);
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n;
	cin>>n;

	for(int i=0;i<n;i++){
		cin>>in[i];
	}
	for(int i=0;i<n;i++){
		cin>>pre[i];
	}
	int index=0;
	fill(level,level+100000,-1);
	print(0,n-1,0,index);//中序下标,前序根节点、层次遍历的序号 
	int cnt=0;
	for(int i=0;;i++){
		if(level[i]!=-1){
			cnt++;
			cout<<level[i];
			if(cnt==n)break;
			cout<<" ";
		}
		
		
	} 
	return 0;
} 

 

map容器(因为层次遍历下标可能很大

#include <bits/stdc++.h>
using namespace std;
const int N=35;

int in[N];//左中右 
int pre[N];//中左右 
//int level[300000];
map<int,int> level;
void print(int l,int r,int root,int index){
	if(l>r)return ;
	int ch=pre[root];
	int i;
	for(i=l;i<=r;i++){
		if(in[i]==ch)break;
	}//in 左l~i-1 中i 右 i+1 ~r ,
//	从而得到左长度 i-l 右长度r-i,从而得到in数组左右段
	level[index]=ch; 

	print(i+1,r,root+i-l+1,index*2+1);
	//右  左+中长度是i-l+1,pre右子树第一个节点是root+i-l+1-1 +1,也就是右子树的根节点 
	print(l,i-1,root+1,index*2+2);
//	由于输出顺序是由下标决定的,先print左子树或是右子树结果一样
//	要镜像翻转,就得把左子树在层次遍历中的序号和右子树交换
//	左子树index*2+2 ,	右子树index*2+1,不是+1和+0,是因为下标从0开始  
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n;
	cin>>n;

	for(int i=0;i<n;i++){
		cin>>in[i];
	}
	for(int i=0;i<n;i++){
		cin>>pre[i];
	}
	int index=0;
	print(0,n-1,0,index);//中序下标,前序根节点、层次遍历的序号 
//	int cnt=0;
//	for(int i=0;i<level.size();i++){
//			cout<<level[i];
//			if(i!=n-1)cout<<" ";
//	}
	map<int,int>::iterator it=level.begin();
	cout<<it->second;
	it++;
	for(;it!=level.end();it++)cout<<" "<<it->second;
	
	return 0;
} 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值