给一个二叉树的中序 + 后续遍历, (通过建树,然后bfs(root)),求出二叉树的层序遍历
- 先由后序找根,再和中序结合建树
- 快速找下根节点是在中序遍历的第几个位置出现的(用哈希表存)看下这个
[左中,当前root]
区间长度是多少,就说明左子树包含多少个点
根据左中的左子树的点数可知后序遍历中,左子树的区间是哪个区间;左子树继续刚才的步骤递归做。右子树也是同理递归做===>这样就可以通过
递归的方式构建二叉树,再从根节点BFS
。
这其中有一步需优化,怎么去找一个节点在中序遍历里是第几个位置出现的?
答:可用哈希表存一下中序遍历里的每个值对应的下标是多少,unordered_map<int,int> pos
#include <iostream>
#include <algorithm>
#include <queue>
#include <unordered_map>
using namespace std;
const int N = 40;
int n;
int postorder[N], inorder[N]; //后序和中序遍历
unordered_map <int, int> l, r, pos;//哈希表l存每个点的左儿子是谁,哈希表r存每个点的右儿子是谁,pos存中序遍历中每个值对应的下标
//返回值是根节点
int build(int il, int ir, int pl, int pr) {
// 中左端 中右端 后左端 后右端
int root = postorder[pr]; //当前根是后序遍历的最后一个位置
int k = pos[root];//中序遍历中根节点的下标,查pos[]哈希表
if (il < k) l[root] = build(il, k - 1, pl, k - 1 - il + pl); //根的左儿子 = 左子树 il < k说明左子树存在,(中序)il, k - 1,(后序) pl, k - 1 - il + pl
if (ir > k) r[root] = build(k + 1, ir, k - il + pl, pr - 1); //根的右儿子 = 右子树
return root;
}
//从根节点开始宽搜
void bfs(int root) {
queue<int> q;
q.push(root); //根节点插入队列
while (q.size()) {//队列非空
auto t = q.front();//取队头
q.pop();//删队头
cout << t << ' ';//输出队头
if (l.count(t)) q.push(l[t]);//如果当前节点存在左子树,就将它的左子树节点l[t]插进队列
if (r.count(t)) q.push(r[t]);//如果当前节点存在右子树,就将它的右子树节点r[t]插进队列
}
}
int main () {
cin >> n;
for (int i = 0; i < n; i ++) cin >> postorder[i]; //读入后序遍历
for (int i = 0; i < n; i ++) {
cin >> inorder[i];
pos[inorder[i]] = i;//哈希表中存中序遍历每个点对应的下标是多少
}
int root = build(0, n - 1, 0, n - 1);//递归构建整棵二叉树 //返回值是根节点
//两组参数分别为为中序遍历区间和后序遍历区间
//两组参数:第一组:当前子树中序遍历是从第几个到第几个位置
//第二组:当前子树后序遍历是从第几个到第几个位置
bfs(root);//重建好二叉树后,从根节点bfs(root),输出层序遍历的结果
return 0;
}