PAT A1020——已知后序中序遍历求层序遍历
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
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn = 50;
struct node {
int data;
node *lchild;
node *rchild;
}; int pre[maxn],in[maxn],post[maxn]; //先序、中序及后序
int n; //结点个数 //当前二叉树的后序序列区间为[postL,postR],中序序列区间为[inL,inR]
//create函数返回构建出的二叉树的根节点地址
node* create(int postL, int postR, int inL, int inR) {
if(postL > postR) {
return NULL; //若后序序列长度小于等于0,则直接返回
}
node* root = new node; //新建一个新的结点,用来存取当前二叉树的根节点
root->data = post[postR]; //新结点的数据域为根节点的值
int k;
for(k = inL; k <= inR; k++) {
if(in[k] == post[postR]) { //在中序序列中找到in[k] == pre[L]的结点
break;
}
}
int numLeft = k - inL; //左子树的结点个数
//返回左子树的根节点地址,赋值给root的左指针
root->lchild = create(postL, postL+numLeft-1, inL, k-1);
//返回右子树的根节点地址,赋值给root的右指针
root->rchild = create(postL+numLeft, postR-1, k+1, inR);
return root; //返回根节点地址
} int num = 0; //已输出的结点个数
void BFS(node* root) {
queue<node*> q;
q.push(root); //将根节点地址入队
while(!q.empty()) {
node* now = q.front(); //取出队首元素
q.pop();
printf("%d",now->data); //访问队首元素
num++;
if(num<n) printf(" ");
if(now->lchild != NULL) q.push(now->lchild);
if(now->rchild != NULL) q.push(now->rchild);
}
} int main() {
scanf("%d", &n);
for(int i=0; i<n; i++) {
scanf("%d", &post[i]);
}
for(int i=0; i<n; i++) {
scanf("%d", &in[i]);
}
node* root = create(0, n-1, 0, n-1); //建树
BFS(root); // 层序遍历
return 0;
}
四种基本的遍历思想为:
前序遍历:根结点 ---> 左子树 ---> 右子树
中序遍历:左子树---> 根结点 ---> 右子树
后序遍历:左子树 ---> 右子树 ---> 根结点
层次遍历:仅仅需按层次遍历就可以
求以下二叉树的各种遍历
前序遍历:1 2 4 5 7 8 3 6
中序遍历:4 2 7 5 8 1 3 6
后序遍历:4 7 8 5 2 6 3 1
层次遍历:1 2 3 4 5 6 7 8
一.前序遍历
前序遍历按照“根结点-左孩子-右孩子”的顺序进行访问。
1.递归实现
1 void preOrder1(BinTree *root) //递归前序遍历
2 {
3 if(root!=NULL)
4 {
5 cout<<root->data<<" ";
6 preOrder1(root->lchild);
7 preOrder1(root->rchild);
8 }
9 }
2.非递归实现
根据前序遍历访问的顺序,优先访问根结点,然后再分别访问左孩子和右孩子。即对于任一结点,其可看做是根结点,因此可以直接访问,访问完之后,若其左孩子不为空,按相同规则访问它的左子树;当访问其左子树时,再访问它的右子树。因此其处理过程如下:
对于任一结点P:
1)访问结点P,并将结点P入栈;
2)判断结点P的左孩子是否为空,若为空,则取栈顶结点并进行出栈操作,并将栈顶结点的右孩子置为当前的结点P,循环至1);若不为空,则将P的左孩子置为当前的结点P;
3)直到P为NULL并且栈为空,则遍历结束。
1 void preOrder2(BinTree *root) //非递归前序遍历
2 {
3 stack<BinTree*> s;
4 BinTree *p=root;
5 while(p!=NULL||!s.empty())
6 {
7 while(p!=NULL)
8 {
9 cout<<p->data<<" ";
10 s.push(p);
11 p=p->lchild;
12 }
13 if(!s.empty())
14 {
15 p=s.top();
16 s.pop();
17 p=p->rchild;
18 }
19 }
20 }
二.中序遍历
中序遍历按照“左孩子-根结点-右孩子”的顺序进行访问。
1.递归实现
1 void inOrder1(BinTree *root) //递归中序遍历
2 {
3 if(root!=NULL)
4 {
5 inOrder1(root->lchild);
6 cout<<root->data<<" ";
7 inOrder1(root->rchild);
8 }
9 }
2.非递归实现
根据中序遍历的顺序,对于任一结点,优先访问其左孩子,而左孩子结点又可以看做一根结点,然后继续访问其左孩子结点,直到遇到左孩子结点为空的结点才进行访问,然后按相同的规则访问其右子树。因此其处理过程如下:
对于任一结点P,
1)若其左孩子不为空,则将P入栈并将P的左孩子置为当前的P,然后对当前结点P再进行相同的处理;
2)若其左孩子为空,则取栈顶元素并进行出栈操作,访问该栈顶结点,然后将当前的P置为栈顶结点的右孩子;
3)直到P为NULL并且栈为空则遍历结束。
1 void inOrder2(BinTree *root) //非递归中序遍历
2 {
3 stack<BinTree*> s;
4 BinTree *p=root;
5 while(p!=NULL||!s.empty())
6 {
7 while(p!=NULL)
8 {
9 s.push(p);
10 p=p->lchild;
11 }
12 if(!s.empty())
13 {
14 p=s.top();
15 cout<<p->data<<" ";
16 s.pop();
17 p=p->rchild;
18 }
19 }
20 }
三.后序遍历
后序遍历按照“左孩子-右孩子-根结点”的顺序进行访问。
1.递归实现
1 void postOrder1(BinTree *root) //递归后序遍历
2 {
3 if(root!=NULL)
4 {
5 postOrder1(root->lchild);
6 postOrder1(root->rchild);
7 cout<<root->data<<" ";
8 }
9 }
2.非递归实现
后序遍历的非递归实现是三种遍历方式中最难的一种。因为在后序遍历中,要保证左孩子和右孩子都已被访问并且左孩子在右孩子前访问才能访问根结点,这就为流程的控制带来了难题。下面介绍两种思路。
第一种思路:对于任一结点P,将其入栈,然后沿其左子树一直往下搜索,直到搜索到没有左孩子的结点,此时该结点出现在栈顶,但是此时不能将其出栈并访问, 因此其右孩子还为被访问。所以接下来按照相同的规则对其右子树进行相同的处理,当访问完其右孩子时,该结点又出现在栈顶,此时可以将其出栈并访问。这样就 保证了正确的访问顺序。可以看出,在这个过程中,每个结点都两次出现在栈顶,只有在第二次出现在栈顶时,才能访问它。因此需要多设置一个变量标识该结点是 否是第一次出现在栈顶。
1 void postOrder2(BinTree *root) //非递归后序遍历
2 {
3 stack<BTNode*> s;
4 BinTree *p=root;
5 BTNode *temp;
6 while(p!=NULL||!s.empty())
7 {
8 while(p!=NULL) //沿左子树一直往下搜索,直至出现没有左子树的结点
9 {
10 BTNode *btn=(BTNode *)malloc(sizeof(BTNode));
11 btn->btnode=p;
12 btn->isFirst=true;
13 s.push(btn);
14 p=p->lchild;
15 }
16 if(!s.empty())
17 {
18 temp=s.top();
19 s.pop();
20 if(temp->isFirst==true) //表示是第一次出现在栈顶
21 {
22 temp->isFirst=false;
23 s.push(temp);
24 p=temp->btnode->rchild;
25 }
26 else //第二次出现在栈顶
27 {
28 cout<<temp->btnode->data<<" ";
29 p=NULL;
30 }
31 }
32 }
33 }
第二种思路:要保证根结点在左孩子和右孩子访问之后才能访问,因此对于任一结点P,先将其入栈。如果P不存在左孩子和右孩子,则可以直接访问它;或者P存 在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,则同样可以直接访问该结点。若非上述两种情况,则将P的右孩子和左孩子依次入栈,这样就保证了 每次取栈顶元素的时候,左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问。
1 void postOrder3(BinTree *root) //非递归后序遍历
2 {
3 stack<BinTree*> s;
4 BinTree *cur; //当前结点
5 BinTree *pre=NULL; //前一次访问的结点
6 s.push(root);
7 while(!s.empty())
8 {
9 cur=s.top();
10 if((cur->lchild==NULL&&cur->rchild==NULL)||
11 (pre!=NULL&&(pre==cur->lchild||pre==cur->rchild)))
12 {
13 cout<<cur->data<<" "; //如果当前结点没有孩子结点或者孩子节点都已被访问过
14 s.pop();
15 pre=cur;
16 }
17 else
18 {
19 if(cur->rchild!=NULL)
20 s.push(cur->rchild);
21 if(cur->lchild!=NULL)
22 s.push(cur->lchild);
23 }
24 }
25 }
PAT A1020——已知后序中序遍历求层序遍历的更多相关文章
- PAT-2019年冬季考试-甲级 7-4 Cartesian Tree (30分)(最小堆的中序遍历求层序遍历,递归建树bfs层序)
7-4 Cartesian Tree (30分) A Cartesian tree is a binary tree constructed from a sequence of distinct ...
- 已知二叉树的中序序列为DBGEAFC,后序序列为DGEBFCA,给出相应的二叉树
面对这种问题时我们该怎么解决? 今天写数据结构题.发现了一道总是碰见问题的题在这里我写了一种求解方法我自己称它为分层递归求解. 第一步通过观察我们知道后序遍历时最后一个是根节点A 在中序序列中A的左边 ...
- ACM题目————已知前序和中序求后序
#include <iostream> #include <cstring> #include <cstdio> using namespace std; ], z ...
- PAT A1020 Tree Traversals (25 分)——建树,层序遍历
Suppose that all the keys in a binary tree are distinct positive integers. Given the postorder and i ...
- PAT 甲级 1020 Tree Traversals (25 分)(二叉树已知后序和中序建树求层序)
1020 Tree Traversals (25 分) Suppose that all the keys in a binary tree are distinct positive integ ...
- PAT Advanced 1020 Tree Traversals (25) [⼆叉树的遍历,后序中序转层序]
题目 Suppose that all the keys in a binary tree are distinct positive integers. Given the postorder an ...
- PAT 甲级 1020 Tree Traversals (25分)(后序中序链表建树,求层序)***重点复习
1020 Tree Traversals (25分) Suppose that all the keys in a binary tree are distinct positive intege ...
- PAT甲级|1151 LCA in a Binary Tree 先序中序遍历建树 lca
给定先序中序遍历的序列,可以确定一颗唯一的树 先序遍历第一个遍历到的是根,中序遍历确定左右子树 查结点a和结点b的最近公共祖先,简单lca思路: 1.如果a和b分别在当前根的左右子树,当前的根就是最近 ...
- 给出 中序&后序 序列 建树;给出 先序&中序 序列 建树
已知 中序&后序 建立二叉树: SDUT 1489 Description 已知一棵二叉树的中序遍历和后序遍历,求二叉树的先序遍历 Input 输入数据有多组,第一行是一个整数t (t& ...
随机推荐
- 14-Java锁的概述
14-锁的概述 乐观锁与悲观锁 乐观锁与悲观锁是数据库中引入的名词,但是在并发包里也引入了类似的思想,在这里我们还是有必要需要了解一下. 悲观锁指数据被外界修改持保守态度,认为数据会很容易被其 ...
- 那些我用Windows时必备的软件
那些我用Windows时必备的软件 使用Windows多年来,自己发现了许多不错的小软件,在此做一个备份清单,方便今后装新机. 起源 \(hadow\)ock$ 越过高墙的小飞机 Google Chr ...
- Flask的环境配置
Flask django是大而全,提供所有常用的功能 flask是小而精,只提供核心功能 环境配置 为了防止 django和 flask环境相互冲突,可以使用 虚拟环境分割开 pip instal ...
- WPF中的命令(Command)
这节来讲一下WPF中的命令(Command)的使用. [认识Command] 我们之前说过,WPF本身就为我们提供了一个基础的MVVM框架,本节要讲的命令就是其中一环,通过在ViewModel中声明命 ...
- python进阶(21)typing模块--类型提示支持
typing介绍 Python是一门弱类型的语言,很多时候我们可能不清楚函数参数的类型或者返回值的类型,这样会导致我们在写完代码一段时间后回过头再看代码,忘记了自己写的函数需要传什么类型的参数,返 ...
- Sobol 序列并行化的实践经验
目录 Sobol 序列并行化的实践经验 随机数发生器并行化的常见策略 Sobol 序列的原理和跳转功能 Sobol 序列并行化实践 分块策略 蛙跳策略 蛙跳策略的计算量分析 减少异或计算的技巧 分块策 ...
- [Git系列] Git 基本概念
版本控制系统 版本控制系统是一种帮助软件开发者实现团队合作和历史版本维护的软件,一个版本控制系统应具备以下列出的这几个基本功能: 允许开发者并发工作: 不允许一个开发者覆写另一个开发者的修改: 保存所 ...
- 【二食堂】Alpha - Scrum Meeting 7
Scrum Meeting 7 例会时间:4.17 11:40 - 12:00 进度情况 组员 昨日进度 今日任务 李健 1. 继续文本区域的开发,先完成目前简陋的添加方式,再区实现勾选功能issue ...
- 通过Nacos动态刷新Spring Cloud Gateway的路由
通过Nacos动态刷新Spring Cloud Gateway的路由 一.背景 二.解决方案 三.实现功能 四.实现步骤 1.网关服务的实现 1.pom文件 2.bootstrap.yml配置文件 3 ...
- 2021.9.20考试总结[NOIP模拟57]
(换个编辑器代码就SB地不自动折叠了.. T1 2A 考察快读的写法. $code:$ T1 #include<bits/stdc++.h> #define scanf SCANF=sca ...