题目

Suppose that all the keys in a binary tree are distinct positive integers. Given the postorder and inorder traversal sequences, you are supposed to output the level order traversal sequence of the corresponding binary tree.

Input Specification:

Each input file contains one test case. For each case, the first line gives a positive integer N (≤30), the total number of nodes in the binary tree. The second line gives the postorder sequence and the third line gives the inorder sequence. All the numbers in a line are separated by a space.

Output Specification:

For each test case, print in one line the level order traversal sequence of the corresponding binary tree. All the numbers in a line must be separated by exactly one space, and there must be no extra space at the end of the line.

Sample Input:

7

2 3 1 5 7 6 4

1 2 3 4 5 6 7

Sample Output:

4 1 6 3 5 7 2

说白了就是,给你一棵二叉树的后序遍历结果和中序遍历结果,让你输出这棵二叉树的层序遍历结果。

题解:

我们应该都接触过由中序遍历和先序遍历得到后序遍历,或者由中序遍历和后序遍历得到先序遍历,其实只要你根据给出的两个序列重构出这棵二叉树,层序遍历也就得到了。

但重构二叉树需要自己创建二叉树的数据结构,还要造一棵树出来,其中指针操作又容易出错,我不想创建树可以吗?可以的!题目只是让我输出最后的遍历结果,又不是让我得到一棵树,我只需要巧妙的调整一下代码就能利用一个map<int, int>得到层序遍历的结果(柳婼大神nb

但不管怎么样,都得先解决一个问题,就是利用中序序列和后序序列怎么得到二叉树呢?这里我简单说一下吧,相信大多数人都会这个操作的。

给个例子:

中序遍历: A D E F G H M Z

后序遍历: A E F D H Z M G

画树求法:

第一步,根据后序遍历的特点,我们知道后序遍历最后一个结点即为根结点,即根结点为G。

第二步,观察中序遍历ADEFGHMZ。其中root节点G左侧的ADEF必然是root的左子树,G右侧的HMZ必然是root的右子树。

第三步,根据后序遍历(左右中)的特点,后序遍历中,根G的左边的节点M必然是它的右子树HMZ的根。

第四步,右子树HMZ有三个节点,根G往左移三个位置后D必然是它的左子树的根

第五步,观察发现,上面的过程是递归的。先找到当前树的根节点,然后划分为左子树,右子树,然后进入左子树重复上面的过程,然后进入右子树重复上面的过程。最后就可以还原一棵树了。该步递归的过程可以简洁表达如下:

1 确定根,确定左子树,确定右子树。

2 在左子树中递归。

3 在右子树中递归。

4 返回或者打印当前根。

层序遍历

那我们一般是怎么是层序遍历,宽度优先遍历,层序其实也就是按顺序,一般都是用一个队列,队列中保存的始终是一整层的姐弟啊,对于每层每个节点,访问自己,把左右孩子加入队列,【保证了访问的先后顺序】

我们这里采用键值对map<int, int>的形式保存,值:节点值,键:层序遍历下它实际的访问序号(下标),对于每个节点,假如编号是i,那么它的左孩子编号是2 * i,右孩子编号是 2*i+1因为键值的大小关系,map会自动按其顺序排序,相当于保证了访问的先后顺序,这样我们最后直接按顺序输出整个map的值,就实现了队列的功能。

但是因为 我们的序列是数组,下标是从0开始的,所以为了避免 2 * 0 = 0节点值覆盖,我们左孩子编号是 2*i+1,右孩子编号是 2*i+2,当然你可以选择让根节点编号是1,就不会有这个问题。

代码实现

#include <iostream>
#include <vector>
#include <map>
using namespace std; // 后续遍历,中序遍历
vector<int> postorder, inorder;
// 层序遍历
map<int, int> level_order; // 因为层序其实也就是按顺序,一般都是用一个队列,对于每层节点,访问自己,把左右孩子加入队列,【保证了访问的先后顺序】
// 我们这里采用键值对<int, int>的形式保存,值:节点值,键:层序遍历下它实际的访问序号(下表)
// 对于每个节点,假如编号是i,那么它的左孩子编号是2 * i,有孩子编号是 2 * i + 1
// 但是因为 我们的下标是从0开始的,所以为了避免 2 * 0 = 0, 我们左孩子编号是 2*i+1,有孩子编号是 2*i+2
// 这样,因为键值的大小关系,map会自动按其顺序排序,相当于保证了访问的先后顺序,这样我们最后直接输出map即可 /**
* in_start 当前子树中序遍历序列在 inorder数组中的起始位置
* in_end 当前子树中序遍历序列在 inorder数组中的结束位置
* post_index 当前子树树根在 postorder数组中的下标
*
* 我们在递归时,每次找到的都是当前树根,然后分别去它的左右子树递归
* 所以我们增加参数 index 保存当前找到的 树根 按层序遍历时它实际的编号(第几个访问),
* 在进入它的左子树时,编号就成了 2 * inedx + 1,递归右子树时 编号就成了 2 * index + 2
*/
void Preorder(int in_start, int in_end, int post_end, int index) {
// 当前子树构建完毕,返回
if (in_start > in_end) return;
int i = in_start;
// post_end总是表示当前子树树根在整棵树后序遍历数组中的下标
// 找到当前子树树根在中序遍历序列中的位置
while (i <= in_end && inorder[i] != postorder[post_end]) i++;
// i 把 [in_start, in_end]划分为 [in_start, i - 1] [i + 1, in_end]两部分
// 其中 [in_start, i - 1] 是当前树根的左子树的中序遍历序列在整棵树的中序遍历序列inorder中的范围
// 其中 [i + 1, in_end] 是当前树根的右子树的中序遍历序列在整棵树的中序遍历序列inorder中的范围
// 根据后续遍历特点(左右中) x x x x x root,当前子树的根是 root,那么 root前一位置就是当前子树的右子树的根
// 加入 右子树有 n个节点,那么 root 往左 n 个位置就是 左子树的树根
level_order[index] = postorder[post_end];
Preorder(in_start, i - 1, post_end - 1 - (in_end - i), 2 * index + 1);
Preorder(i + 1, in_end, post_end - 1, 2 * index + 2);
} int main() { // n个节点
int n;
cin >> n;
// 重新分配大小
postorder.resize(n);
inorder.resize(n);
// 读入后序遍历结果
for (int i = 0; i < n; ++i) cin >> postorder[i];
// 读入中序遍历结果
for (int i = 0; i < n; ++i) cin >> inorder[i];
// 得到层序
Preorder(0, n - 1, n - 1, 0);
// 遍历,注意输出格式,末尾不能有多余空格
auto it = level_order.begin();
cout << it->second;
while (++it != level_order.end())
cout << " " << it->second;
return 0;
}

我的代码其实就是看完柳婼大神的博客后写的,只是她的题解思路很简洁,我的脑子不太够用,就往详细的写了写,如果大家看着繁琐就直接去访问柳神的博客吧!

1020 Tree Traversals (25分)思路分析 + 满分代码的更多相关文章

  1. 1025 PAT Ranking (25分) 思路分析 +满分代码

    题目 Programming Ability Test (PAT) is organized by the College of Computer Science and Technology of ...

  2. PAT 甲级 1020 Tree Traversals (25分)(后序中序链表建树,求层序)***重点复习

    1020 Tree Traversals (25分)   Suppose that all the keys in a binary tree are distinct positive intege ...

  3. PAT 甲级 1020 Tree Traversals (25 分)(二叉树已知后序和中序建树求层序)

    1020 Tree Traversals (25 分)   Suppose that all the keys in a binary tree are distinct positive integ ...

  4. PAT Advanced 1020 Tree Traversals (25 分)

    1020 Tree Traversals (25 分)   Suppose that all the keys in a binary tree are distinct positive integ ...

  5. 1018 Public Bike Management (30分) 思路分析 + 满分代码

    题目 There is a public bike service in Hangzhou City which provides great convenience to the tourists ...

  6. 【PAT甲级】1020 Tree Traversals (25 分)(树知二求一)

    题意: 输入一个正整数N(N<=30),给出一棵二叉树的后序遍历和中序遍历,输出它的层次遍历. trick: 当30个点构成一条单链时,如代码开头处的数据,大约1e9左右的结点编号大小,故采用结 ...

  7. 1020 Tree Traversals (25 分)

    Suppose that all the keys in a binary tree are distinct positive integers. Given the postorder and i ...

  8. 【PAT】1020 Tree Traversals (25)(25 分)

    1020 Tree Traversals (25)(25 分) Suppose that all the keys in a binary tree are distinct positive int ...

  9. PAT Advanced 1020 Tree Traversals (25) [⼆叉树的遍历,后序中序转层序]

    题目 Suppose that all the keys in a binary tree are distinct positive integers. Given the postorder an ...

随机推荐

  1. selenium获取多窗口句柄并一切换至原窗口句柄(三个窗口)

    网上有很多是selenium基于python来获取两个窗口句柄与切换,本文实现用python+selenium获取多窗口句柄并一一切换至原窗口句柄(三个窗口),且在每个窗口下进行一个搜索或翻译,然后截 ...

  2. react-devtools安装调试

    初学react,Chrome F12调试,需要一款插件react-devtools. 网上大多对于翻墙不利索的同学大多才用了git源码.npm本地手动打包Chrome拓展程序.如:https://ww ...

  3. [linux][mysql] 命令更改表结构:添加、删除、修改字段、调整字段顺序

    原文出处:http://www.phpernote.com/MySQL/1120.html 查看表结构: desc tabl_name; show columns fromtable_name: 常用 ...

  4. Netty入门与实战教程总结分享

    前言:都说Netty是Java程序员必须要掌握的一项技能,带着不止要知其然还要知其所以然的目的,在慕课上找了一个学习Netty源码的教程,看了几章后着实有点懵逼.虽然用过Netty,并且在自己的个人网 ...

  5. 基于MySQL Binlog的Elasticsearch数据同步实践

    一.为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品.订单等数据的多维度检索. 使用 Elasticsearch 存储业务数 ...

  6. Ubuntu中安装Hadoop

    安装前 1,更新apt sudo apt-get update   会让你输入密码(自己登录Ubuntu的时候设置的),输入密码不会显示在终端面板上,确定自己敲对之后点回车就行. 2,安装SSH服务器 ...

  7. 从零开始装CentOS以及配置Redis,前端都可以!!!

    ##### 从零开始装CentOS以及配置Redis 1.新建虚拟机 --- ![image](https://img2018.cnblogs.com/blog/1334966/201910/1334 ...

  8. 2、flink入门程序Wordcount和sql实现

    一.DataStream Wordcount 代码地址:https://gitee.com/nltxwz_xxd/abc_bigdata 基于scala实现 maven依赖如下: <depend ...

  9. 2019-2020-1 20199329 第二周测试(环境:ubuntu64位)

    2019-2020-1 20199329 第二周测试(环境:ubuntu64位) 实验一 0.每个.c一个文件,每个.h一个文件,文件名中最好有自己的学号 1.用Vi输入图中代码,并用gcc编译通过 ...

  10. vue2.x学习笔记(二十九)

    接着前面的内容:https://www.cnblogs.com/yanggb/p/12682822.html. 路由 官方路由 对于大多数的单页面应用,都推荐使用官方支持的vue-router库. 从 ...