PAT A1119-根据前序后序序列建树

本文探讨了根据前序和后序遍历序列构造二叉树的问题,分析了序列匹配过程中如何确定树的唯一性及左右子树的划分方法,并提供了一段C++实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意:给出树的节点数,以及前序、后序遍历序列。若树唯一,输出“Yes”,以及中序遍历序列;否则输出“No”,以及任意一个中序遍历序列。
分析

  • 首先回顾 前、中序建树的过程:前序根节点确定,中序不确定,根据前序确定根节点,在中序中找到根,切分左右子树,递归。
  • 在看 前、后序建树,前序、后序根节点都确定了,且一个在最前,一个在最后,无法切分左右子树。但必须得想办法,切分。

为什么前序和后序序列无法确定唯一的二叉树?
前序根节点 preL 的后一个 preL+1,一定是根的孩子(不知左右);后序根节点 postR 的前一个 postR-1 ,一定是根的孩子(不知左右)。

  • pre[preL+1]!=post[postR−1]pre[preL+1] != post[postR-1]pre[preL+1]=post[postR1] 时, => 说明有两个孩子,并且可区分左右,在后序中找到左孩子的根,即可划分出左右子树来。
  • pre[preL+1]==post[postR−1]pre[preL+1] == post[postR-1]pre[preL+1]==post[postR1]时,说明只有一个孩子,但无法确定是左/右孩子,故不唯一!!

由题意可知,当不唯一时,默认将其视为右孩子,建树,中序遍历。

注意点:

  1. 结束条件。尤其是只有一个元素的区间。
  2. 输出格式,最后要输出一个换行才算正确。不知为何,总之养成最后输出空行的习惯吧。

代码:

#include<cstdio>
#include<algorithm>
#define MAXN 50
using namespace std;

int n;
int pre[MAXN];
int post[MAXN];

struct node {
	int data;
	node* lchild;
	node* rchild;
};

bool flag = true;

node* createTree(int preL,int preR,int postL,int postR) {
	if(preL > preR)	return NULL;
	
	// 建立根节点
	node* root  = new node;
	root->data = pre[preL] ;
	
	// 区间长度为 1 时的特判
	if(preL == preR) {
		root->lchild = root->rchild = NULL;
		return root;
	}

	//判断是否有两个孩子
	if(pre[preL+1] != post[postR-1]) {

		// 两个孩子
		// 在后序序列中找左子树的根节点,切分左右子树
		int k = postL;
		while(k < postR && post[k] != pre[preL+1]) k++;
		int numLeft = k - postL + 1;	// 左子树的结点个数

		root->lchild = createTree(preL+1,preL+numLeft,postL,k) ;
		root->rchild = createTree(preL+numLeft+1,preR,k+1,postR-1);

	} else {
		// 一个孩子
		flag = false;

		// 默认当为右孩子来创建
		root->lchild = NULL;
		root->rchild = createTree(preL+1,preR,postL,postR-1);
	}

}

int cnt;
void InOrder(node* root) {
	if(root==NULL)	return ;

	InOrder(root->lchild);
	printf("%d",root->data);
	++cnt;
	if(cnt < n)	printf(" ");
	else printf("\n");
	InOrder(root->rchild);
}

int main() {

//	printf("%d",flag);
	scanf("%d",&n)	;
	for(int i = 0; i < n; ++i) {
		scanf("%d",&pre[i]);
	}
	for(int i = 0; i < n; ++i) {
		scanf("%d",&post[i]);
	}

	node* root = createTree(0,n-1,0,n-1);

	if(flag)
		printf("Yes\n");
	else printf("No\n");

	InOrder(root);

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值