目录
题目
一个二叉树,树中每个节点的权值互不相同。
现在给出它的后序遍历和中序遍历,请你输出它的层序遍历。
输入格式
第一行包含整数 N,表示二叉树的节点数。
第二行包含 N 个整数,表示二叉树的后序遍历。
第三行包含 N个整数,表示二叉树的中序遍历。
输出格式
输出一行 N 个整数,表示二叉树的层序遍历。
数据范围
1≤N≤30
官方并未给出各节点权值的取值范围,为方便起见,在本网站范围取为 1∼N1∼N。
输入样例:
输出样例:
分析题目
思路很简单,根据中序遍历和后序遍历写出层序遍历。我们只需要还原二叉树,再用bfs遍历输出层序遍历。
首先还原二叉树,可以用unordered_map分别建立一个左子树与右子树的map,其中键为当下节点的数据,值为指向下一个节点的数据。然后再来具体看如何建立。后序遍历的最后一个值指向根节点,而中序遍历可以根据已知结点分出左子树和右子树。根据以上信息我们可以用递归还原出二叉树。
其次是层序遍历,运用bfs,用队列储存每一层的节点,然后根据le,ri写出下一节点并储存。
答案
#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;
const int num = 40;
vector<int> posorder(num, 0);//后序遍历
vector<int> inorder(num, 0);//中序遍历
unordered_map<int, int> le, ri;
unordered_map<int, int>in;
int build(int il, int ir, int pl, int pr) {//il,ir用于定中序遍历左右子树区间,pl,pr用于定后序遍历左右子树区间
int root = posorder[pr];
int k = in[root];//获得root在中序遍历的index
//存在左子树
if (il<k) {
le[root] = build(il, k - 1, pl, pl + k - 1 - il);
}
//存在右子树
if (ir > k) {
ri[root] = build(k + 1, ir, pl + (k - il), pr - 1);
}
return root;
}
void bfs(int root) {
queue<int> q;
q.push(root);
while (!q.empty()) {
int t = q.front();
cout << t << ' ';
q.pop();
if (le.count(t)) {//存在左子树
q.push(le[t]);
}
if (ri.count(t)) {//存在右子树
q.push(ri[t]);
}
}
}
int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++)
cin >> posorder[i];
for (int i = 0; i < n; i++) {
cin >> inorder[i];
in[inorder[i]] = i;//便于快速查找到中序值所对应的索引
}
int root = build(0, n - 1, 0, n - 1);//构建二叉树
bfs(root);//层序遍历二叉树
return 0;
}
注意事项
这里使用unordered_map查找速度比map快
inorder在这里可以帮助我们迅速查找到根节点在中序遍历的位置
知识点
还原二叉树:
-
利用中序遍历和后序遍历的特点,分别判断节点的左右位置,父节点
-
先说如何存储树:储存需要具有能区分左右与父子的特点。左右通过建立两个map,键为当前根节点,值则为下一个左/右子树根节点。
-
接下来是如何使用递归存储树:通过后序遍历最后的索引位置获得根节点,如果存在左子树,则将后序与中序定位到左子树区间,返回根节点,右子树同理。
bfs(广度优先搜索)
通过队列的储存,循环读取头节点,并且移除头节点记录头节点指向的下一个结点。