PAT Advance 1119 Pre- and Post-order Traversals (30) [树的遍历,前序后序转中序]
题目
Suppose that all the keys in a binary tree are distinct positive integers. A unique binary tree can be determined by a given pair of postorder and inorder traversal sequences, or preorder and inorder traversal sequences. However, if only the postorder and preorder traversal sequences are given, the corresponding tree may no longer be unique. Now given a pair of postorder and preorder traversal sequences, you are supposed to output the corresponding inorder traversal sequence of the tree. If the tree is not unique, simply output any one of them.
Input Specification:
Each input file contains one test case. For each case, the first line gives a positive integer N (<=30), the total number of nodes in the binary tree. The second line gives the preorder sequence and the third line gives the postorder sequence. All the numbers in a line are separated by a space.
Output Specification:
For each test case, first printf in a line “Yes” if the tree is unique, or “No” if not. Then print in the next line the inorder traversal sequence of the corresponding binary tree. If the solution is not unique, any answer would do. It is guaranteed that at least one solution exists. All the numbers in a line must be separated by exactly one space, and there must be no extra space at the end of the line.
Sample Input 1:
7
1 2 3 4 6 7 5
2 6 7 4 5 3 1
Sample Output 1:
Yes
2 1 6 4 7 3 5
Sample Input 2:
4
1 2 3 4
2 4 3 1
Sample Output 2:
No
2 1 3 4
题目分析
已知前序和后序,打印中序
- 若中序唯一,打印Yes和唯一中序序列
- 若中序不唯一,打印No和任意一个中序序列
注:如何判断中序是否唯一?
在前序序列中,如果当前右子树根节点(当前后序序列倒数第二个节点)左边只有一个节点,则说明当前右子树根节点既可以为其父节点的左孩子节点,也可为其父节点的右孩子节点
如:前序序列1 2 3 4,后序序列2 4 3 1
第一轮:前序序列为1 2 3 4,后序序列为2 4 3 1。后序序列最后一个节点1为根节点,后序序列倒数第二个节点3为1的右子树根节点,查找其在前序序列中其左边有两个节点1,2,则1为根节点,2为1的左子节点,3为1的右子节点
左递归:(处理第一轮中的左子树):前序序列为2,后序序列为2
右递归:(处理第一轮中的右子树):前序序列为3 4,后序序列为4 3。后序序列最后一个节点3为本轮根节点,后序序列倒数第二个节点4为3的右子树根节点,查找其在前序序列中其左边只有一个节点3,3为根节点,4既可以为3的左子节点也可以为3的右子节点(二叉树不唯一,即:中序序列不唯一)
解题思路
思路 01
- 后序序列倒数第一个节点为当前根节点,后序序列倒数第二个节点为当前根节点的右子树根节点
- 先处理当前根节点的左子树,找到最左节点后添加到in中序序列中
- 将1中最左节点的根节点添加到in中序序列中
- 再处理当前根节点的右子树,将其看做一棵树,处理方式同步骤1,2,3(找最左节点及其根节点并处理其右子树)
注:
第一轮
preOrder: 1 2 3 4 6 7 5
postOrder: 2 6 7 4 5 3 1
当前根节点为1,右子树根节点为3,由其在前序序列中的位置可看出,右子树节点包含:3 4 6 7 5,左子树只有一个节点为2
将2入中序序列,之后将1入中序序列(此刻中序序列为:2 1)
第二轮
preOrder: 3 4 6 7 5
postOrder: 6 7 4 5 3
当前根节点为3,右子树只有一个节点为5,由其在前序序列中的位置可看出,左子树根节点为4,左子树节点包含:4 6 7
----递归(处理左子树):找最左节点为6,其根为4,最左节点的父节点的右节点为叶子节7,依次入中序序列(此刻中序序列为:2 1 6 4 7)
继续处理:根节点3入中序序列,其唯一右子树节点5入中序序列(此刻中序序列为:2 1 6 4 7 3 5)
思路 02(容易理解)
- 后序序列倒数第一个节点为当前根节点,后序序列倒数第二个节点为当前根节点的右子树根节点
- 递归查找当前根节点的左右子节点
- 若遇到右子节点前只有一个根节点的情况,说明该右子节点也可为其根节点的左子节点(即:二叉树不唯一,中序序列不唯一),unique标识置为false,并将该节点假设为其根节点的右子节点处理
易错点
1. 最后输出完毕后,必须打印一个换行,否则所有测试点格式错误
Code
Code 01
#include <iostream>
#include <vector>
using namespace std;
const int maxn = 30;
int n,pre[maxn],post[maxn],index;
bool unique=true;
vector<int> in;
void inOrder(int preL,int preR,int postL,int postR) {
// if(preL>preR)return;
if(preL==preR) {
in.push_back(pre[preL]);
return;
}
if(pre[preL]==post[postR]) {
int k=preL+1;
while(k<preR&&pre[k]!=post[postR-1])k++;
if(k-preL>1) {
inOrder(preL+1,k-1,postL,postL+(k-preL-1)-1);
} else {
unique=false;
}
in.push_back(post[postR]);
inOrder(k,preR,postL+(k-preL-1),postR-1);
}
}
int main(int argc,char * argv[]) {
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]);
inOrder(0,n-1,0,n-1);
printf("%s\n%d", unique == true ? "Yes" : "No", in[0]);
for (int i = 1; i < in.size(); i++)
printf(" %d", in[i]);
printf("\n"); //测试发现:最后必须输出换行,否则全部格式错误
return 0;
}
Code 02(容易理解)
#include <iostream>
using namespace std;
const int maxn = 30;
int n,pre[maxn],post[maxn],index;
bool unique=true;
struct node {
int data;
node * left;
node * right;
};
node * create(int preL,int preR,int postL,int postR) {
if(preL>preR)return NULL;
node * root = new node;
root->data=post[postR];
root->left=NULL;
root->right=NULL;
if(preL==preR)return root;
int k=preL+1;
while(k<=preR&&pre[k]!=post[postR-1])k++;
if(k-preL>1) {
root->left=create(preL+1,k-1,postL,postL+(k-preL-1)-1);
root->right=create(k,preR,postL+(k-preL-1),postR-1);
} else {
unique = false;
root->right=create(k,preR,postL+(k-preL-1),postR-1);
}
return root;
}
void inOrder(node * root) {
if(root==NULL)return;
inOrder(root->left);
if(index<n-1)printf("%d ",root->data);
else printf("%d\n",root->data); //测试发现:最后欧必须输出换行,否则全部格式错误
index++;
inOrder(root->right);
}
int main(int argc, char * argv[]) {
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 = create(0,n-1,0,n-1);
printf("%s\n",unique?"Yes":"No");
inOrder(root);
return 0;
}