【PAT甲级题解记录】1020 Tree Traversals (25 分)
前言
Problem:1020 Tree Traversals (25 分)
Tags:树的遍历
Difficulty:
剧情模式想流点汗想流点血死而无憾Address:1020 Tree Traversals (25 分)
问题描述
给定一个二叉树的后序遍历序列 p o s t o r d e r postorder postorder 和中序遍历序列 i n o r d e r inorder inorder,求 层序遍历序列 l e v e l o r d e r levelorder levelorder。
解题思路
-
众所周知,当有中序序列+前序序列或者中序序列+后序序列时就可以生成一个具体的二叉树,本题求层序序列其实就是求生成二叉树按照下标顺序输出而已。
-
已知中前或者中后求二叉树的原理其实一模一样,由于中序序列其每一个根的左子树必在序列前面,右子树必在序列后面,而前序的第一个和后序的最后一个就是根,依靠这俩点就可以生成二叉树。
-
比如 post= “4 5 2 6 7 3 1” ,in = “4 2 5 1 6 3 7” ,那么根据post得知1就是当前二叉树的根,我们在in中找到1,也就得到了in中的左子树"4 2 5" 和右子树"6 3 7",对应到post中就是"4 5 2" 和 “6 7 3”,这是俩个不同顺序的序列俩俩对应的,对于左右分别递归就能生成我们要的二叉树。
-
至于怎么保存这个二叉树,写个结构体有点麻烦了,直接数组存储就可以了,但由于这个二叉树可以很深,那就用map做个离散化,死结点就不放进去了。
-
使用了map后层序遍历,因为map是有序的,而层序其实就是按照结点索引顺序输出,直接遍历map就行。当然用队列去做层遍我也写在了代码中。
(如果要输出前序序列就更简单了,直接生成的时候就可以输出了,只需先输出根节点,再递归生成左右树🌲就可以了,不过我还是写了个前序遍历的函数,这道题用不到但可以简单作为一个测试。)
参考代码
#include<iostream>
#include<map>
#include<vector>
#include<queue>
using namespace std;
int N;
map<int, int> tree;
vector<int> postorder, inorder;
void build_tree(int root, int post_l, int post_r, int in_l, int in_r) {
tree[root] = postorder[post_r]; // 当前根结点是后序序列的最后一个结点
int root_in_inorder = -1; // 根结点在中序序列中的位置
for (int i = in_l; i <= in_r; ++i) {
if (inorder[i] == postorder[post_r]) {
root_in_inorder = i;
break;
}
}
if (root_in_inorder > in_l) { // root有左子树,创建左子树
build_tree(root * 2 + 1, post_l, post_r - (in_r - root_in_inorder + 1), in_l, root_in_inorder - 1);
}
if (root_in_inorder < in_r) { // root有右子树,创建右子树
build_tree(root * 2 + 2, post_r - (in_r - root_in_inorder + 1) + 1, post_r - 1, root_in_inorder + 1, in_r);
}
}
void pre_travel(int root) {
if (tree.count(root) == 0) return;
cout << tree[root] << " ";
pre_travel(root * 2 + 1);
pre_travel(root * 2 + 2);
}
void level_travel() {
queue<int> q;
q.push(0);
cout << tree[0];
while (!q.empty()) {
int top = q.front();
if (top != 0) {
cout << " " << tree[top];
}
q.pop();
if (tree.count(top * 2 + 1)) {
q.push(top * 2 + 1);
}
if (tree.count(top * 2 + 2)) {
q.push(top * 2 + 2);
}
}
cout<<endl;
// 由于map自带排序,而层序遍历就是结点的下标从小到大遍历,故直接按照map中的顺序输出就是层序遍历
// for (map<int, int>::iterator iter = tree.begin(); iter != tree.end(); ++iter) {
// if(iter!=tree.begin()) cout<<" ";
// cout<<iter->second;
// }
// cout<<endl;
}
void init() {
cin >> N;
postorder.resize(N, 0);
inorder.resize(N, 0);
for (int i = 0; i < N; ++i) {
cin >> postorder[i];
}
for (int i = 0; i < N; ++i) {
cin >> inorder[i];
}
build_tree(0, 0, N - 1, 0, N - 1);
}
void solution_1020() {
init();
// pre_travel(0);
// cout << endl;
level_travel();
}
int main() {
solution_1020();
return 0;
}