P1497 树的遍历
- 树的遍历性问题,唯一难点是:得到左。有子树的对应的范围区间;当得到了左右子树的区间后,无脑递归结束;
- 由于这里还涉及到前序、后序序列,所以左右子树的范围在2个序列中都要表示出来,因此指针数量*2;
在2个序列中分别表示出当前树的范围(即区间的范围)即可。
算法1 (DFS建树、BFS搜索层序遍历) O(n)
O(n)
C++ 代码
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
const int N = 50;
int n;
int a[N], b[N];
int ltree[N], rtree[N];
int dfs(int pl, int pr, int ll, int lr)
{
int root = a[lr];
if(pl > pr || ll > lr) return 0;
int mid = 0;
for(int i = pl; i<=pr; ++i){
if(b[i] == root){
mid = i;
break;
}
}
ltree[root] = dfs(pl,mid-1,ll,ll+mid-pl-1);
rtree[root] = dfs(mid+1,pr,ll+mid-pl-1+1,lr-1);
return root;
}
void bfs(int u)
{
queue<int> q;
q.push(u);
cout << u;
while(q.size()){
int t = q.front();
if(t != u) printf(" %d", t);
q.pop();
if(ltree[t]) q.push(ltree[t]);
if(rtree[t]) q.push(rtree[t]);
}
}
int main()
{
cin >> n;
for(int i = 0; i<n; ++i) cin >> a[i];
for(int i = 0; i<n; ++i) cin >> b[i];
bfs(dfs(0,n-1,0,n-1));
return 0;
}
算法2 (DFS建树、map存二叉树) O(n)
- 注意到这是一颗二叉树,所以可以直接用下标关系把结点存在map中, 省去BFS的过程。但要注意题目并没有说这不是完全二叉树,所以必须用map存树上结点对应的元素,因为有些结点会是空结点,用数组会打印出0.用map没插入的元素不会打印出来。
- 提起用hash表记录中序序列中各个元素的位置,这样后序在中序序列中查询根结点的时间:O(1)
C++ 代码
#include <iostream>
#include <vector>
#include <unordered_map>
#include <queue>
#include <map>
using namespace std;
const int N = 50;
int n;
int a[N], b[N];
map<int,int> ans;
unordered_map<int,int> pos;
void dfs(int pl, int pr, int ll, int lr, int id)
{
int root = a[lr];
if(pl > pr) return ;
int mid = pos[root];
ans[id] = root;
dfs(pl,mid-1,ll,ll+mid-pl-1, id*2);
dfs(mid+1,pr,ll+mid-pl-1+1,lr-1, id*2+1);
}
int main()
{
cin >> n;
for(int i = 0; i<n; ++i) cin >> a[i];
for(int i = 0; i<n; ++i){
cin >> b[i];
pos[b[i]] = i;
}
dfs(0,n-1,0,n-1,1);
for(auto v : ans) cout << v.second << ' ';
return 0;
}