解题报告-PAT- Tree Traversals Again(1086)

解题报告-PAT- Tree Traversals Again
Tree Traversals Again有两种解题思路:
1、在Push和Pop的过程中记录后序序列。
2、构造先序序列和中序序列,然后build后序序列。

PAT原题链接:https://www.patest.cn/contests/pat-a-practise/1086
下面给出两种算法:
算法1:
# include <stdio.h>
# include <string.h>
# include <iostream>
# define MAX 60

typedef struct stack{
	int top;
	int data[MAX];
	int flag[MAX];  //标记变量 0.表示在访问左子树,1.表示在访问右子树。只有在访问右子树弹出栈的时候才输出 
}ST;
/**
算法思想:
	一个入栈出栈序列,之所以能唯一确定一颗树,就是因为,入栈顺序是中序遍历,出栈顺序是先序遍历。
而先序中序可以唯一确定一颗树,那么这里我们就有两种思路:
1.先保存先序遍历序列和中序遍历序列,递归调用build(n,s1,s2,ans);求解后序遍历序列。
2.没必要保存,在Push和Pop的过程中暗含了一些顺序信息。
	新建栈s。 
	当中序遍历Push时,说明在访问左子树,这时候我们把节点放入堆栈,并设置标签0,表示在访问左子树的过程中。
当中序遍历Pop时,说明是左子树访问完毕返回的情况,我们并不真的pop s的元素,而是把s的栈顶元素设置为1,表示现在这个节点
在中序遍历中已出栈,在访问右孩子的过程中。在设置栈顶元素为1之前要先pop掉所有栈顶为1的元素,这些元素已经是确定的
后序遍历序列。
输入为Push: 那么往s里面push,同时标记0
输入为Pop:  那么先从堆栈s里面pop出标记为1的节点,从栈顶开始,到标记为0结束,同时输出。再把栈顶元素设置为1,表示要访问
			栈顶元素的右孩子。 
**/ 
ST s;   //定义栈 
int main(){
	char str[10];
	int t, n, ans[MAX], j=0;
	cin >> n;

	s.top = 0;   //代表栈中有0个元素 
	for(int i = 0; i < MAX; i++){
		s.flag[i] = 0;
	}
	for(int i = 0;i < 2*n; i++){
		cin >> str;
		if(strcmp(str,"Push") == 0){ //直接push 
			cin >> t;
			s.data[s.top] = t;
			s.flag[s.top++] = 0;

		}else{ //输入的是pop 
			//弹出栈顶标记为1的元素 
			while(s.top!=0){
				if(s.flag[s.top-1] == 1)
					ans[j++] = s.data[--s.top];
				else
					break;
			}
			s.flag[s.top-1] = 1; //栈顶元素设置为1表示继续访问栈顶的右孩子。 
		}
	}
	while(s.top!=0) //栈中还有元素未出栈,依次出栈 
		ans[j++] = s.data[--s.top];
	
	for(int i=0;i<n;i++){
		if(i) printf(" ");
		printf("%d",ans[i]);	
	} 
	return 0;
} 

算法2:
# include <stdio.h>
# include <string.h>
# include <iostream>
# include <stack>
# define MAX 60
using namespace std;

stack<int> s;
void build(int n,char *s1,char* s2,char *s){
	if(n<=0) //没有节点要转换 
		return;
	int p=strchr(s2,s1[0]) - s2; //寻找s1[0]在s2中的下标
	build(p,s1+1,s2,s);
	build(n-p-1,s1+p+1,s2+p+1,s+p); //递归求右边n-p-1个节点
	s[n-1]=s1[0]; 
}
int main(){
	char str[5];
	int s1[MAX],s2[MAX];
	int j1=0,j2=0,t,n;
	cin >> n;
	for(int i=0;i<2*n;i++){
		cin>>str;
		if(strcmp(str,"Push") == 0){
			cin>>t;
			s.push(t);
			s1[j1++] = t;
		}else{
			s2[j2++]=s.top();
			s.pop();
		}
	}
	char str1[MAX],str2[MAX],ans[MAX];
	for(int i=0;i<n;i++){
		str1[i] = s1[i]+'0';
		str2[i] = s2[i]+'0';
	}
	
	build(n,str1,str2,ans);
	ans[n]='\0';
	for(int i=0;i<n;i++){
		if(i) printf(" ");
		printf("%c",ans[i]);
	}
	printf("\n");
	return 0;
} 
其中算法2在PAT的提交测试中,N=30,复杂组合,测试点5没有通过。留待后序研究,或者有知道原因的也可以联系我。





评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

随风浪仔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值