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& ...
随机推荐
- Django整理(五) - 请求与响应 - request对象
请求对象 一.客户端传参的几种方式 1. 通过URL路径(path)传递,例如:http://127.0.0.1:8000/news/1/2,两个参数:id和page 2. 通过 query stri ...
- SAE助力南瓜电影7天内全面Severless
作者:李刚(寻如),阿里云解决方案架构师 南瓜电影APP是国内领先的专注于影视精品化运营的垂直类视频产品,在移动互联网.IPTV.OTT等客户端,面向广大中产阶级精英群体,提供有异于院线及其他视频平台 ...
- FastAPI 学习之路(十)请求体的字段
系列文章: FastAPI 学习之路(一)fastapi--高性能web开发框架 FastAPI 学习之路(二) FastAPI 学习之路(三) FastAPI 学习之路(四) FastAPI 学习之 ...
- Mybatis、maven项目中整合log4j (17)
Mybatis.maven项目总整合log4j java 中Mybatis.maven项目总整合log4j 1.pom增加log4j包引用 2.添加 log4j.properties文件 # java ...
- UE4蓝图AI角色制作(六)之行为树
13.行为树原理 AI最重要的环节就是行为树.我们将解释什么是行为树.为何它如此重要,以及构建行为树需要哪些元素. 借助行为树,我们可以轻松控制并显示AI的决策制定过程.行为树是一种将AI在场景中的决 ...
- ubuntu20.04 使用root用户登录
1.设置root用户密码 执行 sudo passwd root 然后输入设置的密码,输入两次,这样就完成了设置root用户密码了 2.修改配置文件 执行 sudo vim /usr/share/li ...
- 验证域用户(C#)
代码如下: using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Intero ...
- Java中类及方法的加载顺序
1. 虚拟机在首次加载Java类时,会对静态代码块.静态成员变量.静态方法进行一次初始化(静态间按顺序执行). 2. 只有在调用new方法时才会创建类的实例. 3. 类实例创建过程:父子继承关系,先父 ...
- [对对子队]会议记录4.12(Scrum Meeting 3)
今天已完成的工作 朱骏豪 工作内容:找到了游戏的背景场景,用PS扣了按钮的图 相关issue:实现UI的美术需求 实现游戏场景中的必要模型 梁河览 工作内容:将关卡选择界面和欢迎界面导入项 ...
- Noip模拟49 2021.9.7
T1 reverse 又一道板子打假的挂分题,直接挂到倒二.. 考场上思路神奇,居然想到用$bfs$建边然后跑最短路, 其实当时也想到了直接$bfs$,但是不知道为啥觉得$dij$屌就没直接打$bfs ...