原文链接: PAT A1020. Tree Traversals (25)
上一篇: PAT A1091. Acute Stroke (30)
下一篇: PAT A1086. Tree Traversals Again (25)
1020. Tree Traversals (25)
https://www.patest.cn/contests/pat-a-practise/1020
时间限制
400 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue
Suppose that all the keys in a binary tree are distinct positive integers. Given the postorder and inorder traversal sequences, you are supposed to output the level order traversal sequence of the corresponding binary tree.
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 postorder sequence and the third line gives the inorder sequence. All the numbers in a line are separated by a space.
Output Specification:
For each test case, print in one line the level order traversal sequence of the corresponding binary tree. 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:
7 2 3 1 5 7 6 4 1 2 3 4 5 6 7
Sample Output:
4 1 6 3 5 7 2
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int MAX = 50;
struct Node {
int data;
Node *left, *right;
Node() {}
Node(int data) :data(data) {
left = right = NULL;
}
};
int pre[MAX], in[MAX], post[MAX]; //先序,中序,后序序列
int n; //节点个数
//当前二叉树的后序序列区间[postL,postR],中序区间[inL,inR]
Node* create(int postL, int postR, int inL, int inR) {
if (postL > postR) return NULL;
Node *root = new Node(post[postR]);
int k;
for (k = inL; k <= inR; k++) {
if (in[k] == post[postR])
break; //在中序中找in[k] == pre[l]的节点
}
int numLeft = k - inL; //左子树节点个数
root->left = create(postL, postL + numLeft - 1, inL, k - 1);
root->right = create(postL + numLeft, postR - 1, k + 1, inR);
return root;
}
int num = 0; //已输出节点个数
void bfs(Node* root) {
queue<Node*> q;
q.push(root);
while (!q.empty()) {
Node *now = q.front();
q.pop();
printf("%d", now->data);
num++;
if (num < n) printf(" ");
if (now->left) q.push(now->left);
if (now->right) q.push(now->right);
}
}
int main(int argc, char *argv[]) {
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d", post + i);
}
for (int i = 0; i < n; i++)
scanf("%d", in + i);
Node *root = create(0, n - 1, 0, n - 1);
bfs(root);
return 0;
}
不用建树的做法
已知后序与中序输出前序(先序):
后序:3, 4, 2, 6, 5, 1(左右根)
中序:3, 2, 4, 1, 6, 5(左根右)
分析:因为后序的最后一个总是根结点,令i在中序中找到该根结点,则i把中序分为两部分,左边是左子树,右边是右子树。因为是输出先序(根左右),所以先打印出当前根结点,然后打印左子树,再打印右子树。左子树在后序中的根结点为root – (end – i + 1),即为当前根结点-右子树的个数。左子树在中序中的起始点start为start,末尾end点为i – 1.右子树的根结点为当前根结点的前一个结点root – 1,右子树的起始点start为i+1,末尾end点为end。
输出的前序应该为:1, 2, 3, 4, 5, 6(根左右)
#include <cstdio>
using namespace std;
int post[] = {3, 4, 2, 6, 5, 1};
int in[] = {3, 2, 4, 1, 6, 5};
void pre(int root, int start, int end) {
if(start > end) return ;
int i = start;
while(i < end && in[i] != post[root]) i++;
printf("%d ", post[root]);
pre(root - 1 - end + i, start, i - 1);
pre(root - 1, i + 1, end);
}
int main() {
pre(5, 0, 5);
return 0;
}
题目大意:给定一棵二叉树的后序遍历和中序遍历,请你输出其层序遍历的序列。这里假设键值都是互不相等的正整数。
分析:与后序中序转换为前序的代码相仿(无须构造二叉树再进行广度优先搜索~~),只不过加一个变量index,表示当前的根结点在二叉树中所对应的下标(从0开始),所以进行一次输出先序的递归的时候,就可以把根结点下标所对应的值存储在level数组中(一开始把level都置为-1表示此处没有结点),这样在递归完成后level数组中非-1的数就是按照下标排列的层序遍历的顺序~~~
#include <cstdio>
#include <vector>
using namespace std;
vector<int> post, in, level(100000, -1);
void pre(int root, int start, int end, int index) {
if(start > end) return ;
int i = start;
while(i < end && in[i] != post[root]) i++;
level[index] = post[root];
pre(root - 1 - end + i, start, i - 1, 2 * index + 1);
pre(root - 1, i + 1, end, 2 * index + 2);
}
int main() {
int n, cnt = 0;
scanf("%d", &n);
post.resize(n);
in.resize(n);
for(int i = 0; i < n; i++) scanf("%d", &post[i]);
for(int i = 0; i < n; i++) scanf("%d", &in[i]);
pre(n-1, 0, n-1, 0);
for(int i = 0; i < level.size(); i++) {
if(level[i] != -1 && cnt != n - 1) {
printf("%d ", level[i]);
cnt++;
} else if(level[i] != -1){
printf("%d", level[i]);
break;
}
}
return 0;
}