【树的遍历】

发布于:2024-08-10 ⋅ 阅读:(49) ⋅ 点赞:(0)

题目

代码

#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]);
    }
}