【PAT甲级题解记录】1020 Tree Traversals (25 分)

【PAT甲级题解记录】1020 Tree Traversals (25 分)

前言

Problem:1020 Tree Traversals (25 分)

Tags:树的遍历

Difficulty:剧情模式 想流点汗 想流点血 死而无憾

Address:1020 Tree Traversals (25 分)

问题描述

给定一个二叉树的后序遍历序列 p o s t o r d e r postorder postorder 和中序遍历序列 i n o r d e r inorder inorder,求 层序遍历序列 l e v e l o r d e r levelorder levelorder

解题思路

  1. 众所周知,当有中序序列+前序序列或者中序序列+后序序列时就可以生成一个具体的二叉树,本题求层序序列其实就是求生成二叉树按照下标顺序输出而已。

  2. 已知中前或者中后求二叉树的原理其实一模一样,由于中序序列其每一个根的左子树必在序列前面,右子树必在序列后面,而前序的第一个和后序的最后一个就是根,依靠这俩点就可以生成二叉树。

  3. 比如 post= “4 5 2 6 7 3 1” ,in = “4 2 5 1 6 3 7” ,那么根据post得知1就是当前二叉树的根,我们在in中找到1,也就得到了in中的左子树"4 2 5" 和右子树"6 3 7",对应到post中就是"4 5 2" 和 “6 7 3”,这是俩个不同顺序的序列俩俩对应的,对于左右分别递归就能生成我们要的二叉树。

  4. 至于怎么保存这个二叉树,写个结构体有点麻烦了,直接数组存储就可以了,但由于这个二叉树可以很深,那就用map做个离散化,死结点就不放进去了。

  5. 使用了map后层序遍历,因为map是有序的,而层序其实就是按照结点索引顺序输出,直接遍历map就行。当然用队列去做层遍我也写在了代码中。

(如果要输出前序序列就更简单了,直接生成的时候就可以输出了,只需先输出根节点,再递归生成左右树🌲就可以了,不过我还是写了个前序遍历的函数,这道题用不到但可以简单作为一个测试。)

参考代码

#include<iostream>
#include<map>
#include<vector>
#include<queue>

using namespace std;
int N;
map<int, int> tree;
vector<int> postorder, inorder;


void build_tree(int root, int post_l, int post_r, int in_l, int in_r) {
    tree[root] = postorder[post_r]; // 当前根结点是后序序列的最后一个结点
    int root_in_inorder = -1; // 根结点在中序序列中的位置
    for (int i = in_l; i <= in_r; ++i) {
        if (inorder[i] == postorder[post_r]) {
            root_in_inorder = i;
            break;
        }
    }
    if (root_in_inorder > in_l) { // root有左子树,创建左子树
        build_tree(root * 2 + 1, post_l, post_r - (in_r - root_in_inorder + 1), in_l, root_in_inorder - 1);
    }
    if (root_in_inorder < in_r) { // root有右子树,创建右子树
        build_tree(root * 2 + 2, post_r - (in_r - root_in_inorder + 1) + 1, post_r - 1, root_in_inorder + 1, in_r);
    }
}

void pre_travel(int root) {
    if (tree.count(root) == 0) return;
    cout << tree[root] << " ";
    pre_travel(root * 2 + 1);
    pre_travel(root * 2 + 2);
}

void level_travel() {
    queue<int> q;
    q.push(0);
    cout << tree[0];
    while (!q.empty()) {
        int top = q.front();
        if (top != 0) {
            cout << " " << tree[top];
        }
        q.pop();
        if (tree.count(top * 2 + 1)) {
            q.push(top * 2 + 1);
        }
        if (tree.count(top * 2 + 2)) {
            q.push(top * 2 + 2);
        }
    }
    cout<<endl;
    // 由于map自带排序,而层序遍历就是结点的下标从小到大遍历,故直接按照map中的顺序输出就是层序遍历

//    for (map<int, int>::iterator iter = tree.begin(); iter != tree.end(); ++iter) {
//        if(iter!=tree.begin()) cout<<" ";
//        cout<<iter->second;
//    }
//    cout<<endl;

}

void init() {
    cin >> N;
    postorder.resize(N, 0);
    inorder.resize(N, 0);
    for (int i = 0; i < N; ++i) {
        cin >> postorder[i];
    }
    for (int i = 0; i < N; ++i) {
        cin >> inorder[i];
    }
    build_tree(0, 0, N - 1, 0, N - 1);
}


void solution_1020() {
    init();
//    pre_travel(0);
//    cout << endl;
    level_travel();
}
int main() {
    solution_1020();
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值