题目
代码
#include<bits/stdc++.h>
using namespace std;const int N = 40;int in[N], pos[N]; //中序、后序
int idx[N]; //中序的值->索引
unordered_map<int, int> l, r; //根节点的左、右树根节点
int n;
int build(int il, int ir, int pl, int pr)
{int root = pos[pr];int k = idx[root];if(il < k) l[root] = build(il, k-1, pl, pl + k - 1 - il);if(k < ir) r[root] = build(k+1, ir, pl + k - 1 - il + 1, pr-1);return root;
}
void bfs(int root)
{queue<int> q;q.push(root);while(!q.empty()){int fr = q.front();cout << fr << " ";q.pop();if(l.count(fr)) q.push(l[fr]);if(r.count(fr)) q.push(r[fr]);}
}
int main()
{cin >> n;for(int i = 1; i <= n; i++) cin >> pos[i];for(int i = 1; i <= n; i++) cin >> in[i], idx[in[i]] = i;int root = build(1, n, 1, n);bfs(root);return 0;
}
思考
对于树的遍历,算法应设计如下
层序:bfs(queue)
先序:dfs(递归) (先输出) or dfs(stack)(不论先后输出)
中序:dfs(递归)(中间输出)
后序:dfs(递归)(后面输出)
理解
queue+先左再右就可以保证同一层中从左到右,不同层之间从上到下。
根据序列遍历的要求,要先左根再右根。所以递归要先左再右。
但是用stack模拟要反着来,先压入右节点,再压入左节点。然后左节点出又是如此,这样就像上面那个先左再右,右生左继续先左再右了。
提一个问题:为什么递归中改变输出的时机可以在不同序列间切换,但是在stack中不行?
答:递归中的子递归也有输出操作,从代码上看,就像左子输出、右子输出和根节点输出在排序一样;而stack中的输出就是当前top节点的值(不是递归,没有子输出),于是输出顺序和访问顺序相同,是定死的先序。要改变序列,必须从访问顺序上下手
补充
(递归,先中后序列)
void firsto(int root)
{cout << root << " ";if(l.count(root)) firsto(l[root]);if(r.count(root)) firsto(r[root]);
}
void ino(int root)
{if(l.count(root)) ino(l[root]);cout << root << " ";if(r.count(root)) ino(r[root]);
}
void poso(int root)
{if(l.count(root)) poso(l[root]);if(r.count(root)) poso(r[root]);cout << root << " ";
}
(stack,先序)
void first_dfs(int root)
{stack<int> s;s.push(root);while(!s.empty()){int fr = s.top();cout << fr << " ";s.pop();if(r.count(fr)) s.push(r[fr]);if(l.count(fr)) s.push(l[fr]);}
}