已知二叉树中序遍历及后序遍历序列求层序遍历序列 | 数据结构

315 阅读2分钟

题目来源:1497. 树的遍历 - AcWing题库

一个二叉树,树中每个节点的权值互不相同。

现在给出它的后序遍历和中序遍历,请你输出它的层序遍历。

输入格式

第一行包含整数 NN,表示二叉树的节点数。

第二行包含 NN 个整数,表示二叉树的后序遍历。

第三行包含 NN 个整数,表示二叉树的中序遍历。

输出格式

输出一行 NN 个整数,表示二叉树的层序遍历。

数据范围

1N301\leq N \leq 30

官方并未给出各节点权值的取值范围,为方便起见,在本网站范围取为 1N1\sim N

输入样例:

7
2 3 1 5 7 6 4
1 2 3 4 5 6 7

输出样例:

4 1 6 3 5 7 2

题解

  1. main() 读入后序遍历中序遍历序列,用哈希表记录中序遍历所有节点的下标
  2. build() 递归建树,返回树根
  3. bfs() 层序遍历输出结果
#include <iostream>
#include <unordered_map>
#include <queue>

using namespace std;

const int N = 40;

// 节点左孩子,节点右孩子,节点在中序遍历数组中的下标
unordered_map<int, int> l, r, pos;

// 后序遍历、中序遍历的顺序
int postorder[N], inorder[N];

// 递归建树:中序遍历左端点、中序遍历右端点、后序遍历左端点、后序遍历右端点
int build(int il, int ir, int pl, int pr)
{
    /*
    后序遍历的右端点处的元素是根节点
    左边被分成两段:第一段是左子树的后序遍历,第二段是右子树的后序遍历
    */
    int root = postorder[pr];
    /*
    记录根节点在中序遍历数组中的下标
    */
    int k = pos[root];
    /*
    如果左边是一棵子树不是一个叶节点,递归求解root的左孩子
    左子树在中序遍历数组的左端点为 il ,右端点为 k - 1
    左子树在后序遍历数组的左端点为 pl ,右端点为 pl + k - 1 - il
    (设左子树在后序遍历数组的右端点为 x ,则由子数组长度相等列出方程 x - pl = k - 1 - il)
    */
    if (il < k) l[root] = build(il, k - 1, pl, pl + k - 1 - il);
    /*
    如果右边是一棵子树不是一个叶节点,递归求解root的右孩子
    右子树在中序遍历数组的左端点为 k + 1 ,右端点为 ir
    右子树在后序遍历数组的左端点为 pl + k - 1 - il + 1 ,右端点为 pr - 1
    (右子树在后序遍历数组的左端点比左子树在后序遍历数组的右端点多 1)
    */
    if (ir > k) r[root] = build(k + 1, ir, pl + k - il, pr - 1);
    /*
    返回当前已经构建好的子树
    */
    return root;
}

// 层序遍历输出树
void bfs(int root)
{
    queue<int> q; // 广度优先遍历
    q.push(root); // 根节点入队
    // 队列不为空就一直循环
    while (q.size()) {
        int t = q.front(); // 队首元素出队
        q.pop();
        // 如果存在左子树
        if (l.count(t)) q.push(l[t]); // 左子树入队
        // 如果存在右子树
        if (r.count(t)) q.push(r[t]); // 右子树入队
        // 输出层序遍历的结果
        cout << t << ' ';
    }
}

int main()
{
    int n;
    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);
    return 0;
}