CCCC团体程序设计天梯赛 L2-006 树的遍历
记录天梯赛题目合集 跳转查看
题目描述
给定一棵二叉树的后序遍历和中序遍历,请你输出其层序遍历的序列。这里假设键值都是互不相等的正整数。
输入格式:
输入第一行给出一个正整数\(N(≤30)\),是二叉树中结点的个数。第二行给出其后序遍历序列。第三行给出其中序遍历序列。数字间以空格分隔。
输出格式:
在一行中输出该树的层序遍历的序列。数字间以\(1\)个空格分隔,行首尾不得有多余空格。
输入样例:
7
2 3 1 5 7 6 4
1 2 3 4 5 6 7
输出样例:
4 1 6 3 5 7 2
题目分析
题面很简单,已知二叉树的后序遍历和中序遍历,求二叉树的层序遍历。
首先,必须了解什么是二叉树的后序遍历、中序遍历、层序遍历,后序遍历就是按左子树、右子树、根节点的顺序逐次遍历二叉树,中序遍历则是按左子树、根节点、右子树的顺序逐次遍历二叉树,层序遍历则是树的每层按从左到右的顺序遍历二叉树。
了解了遍历的规则后,我们就可以通过遍历的顺序来确定树,因为后序遍历是最后才遍历根节点,这就意味着树的根节点是最后一个,而根据中序遍历的规则,位于根节点左边的都是左子树的结点,位于右边的都是右子树的结点。
如题目样例:4是根节点,中序遍历中位于4左边的1 2 3都是左子树上的点,位于4右边的5 6 7都是右子树上的点;由此再回到后序,1 2 3中1位于末尾是左子树的根节点,在中序中2 3都在右边意味2 3都是1 的右子树上的点,以此类推。
可以发现,我们是根据后序遍历确定根节点,根据中序遍历确定左右子树的结点,最终构建完整的树,那么我们怎么样可以在构建树的过程中就完成树的层序遍历呢?我们观察二叉树的层序遍历(从1开始编号),发现每个左儿子结点的编号是父节点编号的两倍,右儿子结点的编号是父节点编号的两倍再加一,我们只需要在构建树的过程中给每个结点确定一个层序遍历的编号,最后按编号大小输出,就完成了层序遍历。
代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const ll inf = 1e18;
const int INF = 0x3f3f3f3f;
const int N = 1e6 + 10;
const int M = 100 + 10;
int post[M], in[M];
map<int, int> ans;
int n;
bool find(int root, int st, int ed, int idx)
{
if (st > ed) return false;
ans[idx] = post[root]; // 后序遍历中确定根节点
int i = st;
while (i <= ed && in[i] != post[root]) i ++; // 枚举确定左右子树结点的范围
idx <<= 1; // 层序遍历的编号
if (find(root - 1 - (ed - i), st, i - 1, idx)) idx |= 1; // 先递归左子树,如果左子树存在的话
find(root - 1, i + 1, ed, idx);
return true;
}
void solve()
{
cin >> n;
for (int i = 1; i <= n; i ++) cin >> post[i];
for (int i = 1; i <= n; i ++) cin >> in[i];
find(n, 1, n, 1);
bool flag = 0;
for (auto i : ans)
{
if (flag) cout << ' ';
else flag = 1;
cout << i.second;
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
int T = 1;
// cin >> T;
while (T --) solve();
return 0;
}

浙公网安备 33010602011771号