1020 Tree Traversals

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——已知后序中序遍历求层序遍历的更多相关文章

  1. 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 ...

  2. 已知二叉树的中序序列为DBGEAFC,后序序列为DGEBFCA,给出相应的二叉树

    面对这种问题时我们该怎么解决? 今天写数据结构题.发现了一道总是碰见问题的题在这里我写了一种求解方法我自己称它为分层递归求解. 第一步通过观察我们知道后序遍历时最后一个是根节点A 在中序序列中A的左边 ...

  3. ACM题目————已知前序和中序求后序

    #include <iostream> #include <cstring> #include <cstdio> using namespace std; ], z ...

  4. PAT A1020 Tree Traversals (25 分)——建树,层序遍历

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

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

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

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

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

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

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

  8. PAT甲级|1151 LCA in a Binary Tree 先序中序遍历建树 lca

    给定先序中序遍历的序列,可以确定一颗唯一的树 先序遍历第一个遍历到的是根,中序遍历确定左右子树 查结点a和结点b的最近公共祖先,简单lca思路: 1.如果a和b分别在当前根的左右子树,当前的根就是最近 ...

  9. 给出 中序&后序 序列 建树;给出 先序&中序 序列 建树

    已知 中序&后序  建立二叉树: SDUT 1489 Description  已知一棵二叉树的中序遍历和后序遍历,求二叉树的先序遍历 Input  输入数据有多组,第一行是一个整数t (t& ...

随机推荐

  1. mysql从零开始之MySQL 创建数据库

    MySQL 创建数据库 我们可以在登陆 MySQL 服务后,使用 create 命令创建数据库,语法如下: CREATE DATABASE 数据库名; 以下命令简单的演示了创建数据库的过程,数据名为 ...

  2. Java基础之(十三):类与对象

    初识面向对象 面向对象 & 面向过程 面向过程思想 步骤清晰简单,第一步做什么,第二步做什么..... 面向过程适合处理一些较为简单的问题 面向对象思想 ​ 物以类聚,分类的思维模式,思考问题 ...

  3. 题解 2020.10.24 考试 T4 模板

    题目传送门 题目大意 有一个 \(n\) 个点组成的树,有 \(m\) 次操作,每次将 \(1\to x\) 的路径上每个点都加入一个颜色为 \(c\) 的小球.但是每个点都有大小限制,即小球个数超过 ...

  4. Vuls 漏洞扫描工具部署及效果展示

    Vuls 漏洞扫描工具部署及效果展示 介绍 Vuls根据NVD,OVAL等数据对主流Linux系统进行扫描,并具有完善的报告. 支持系统 Distribution Release Alpine 3.3 ...

  5. C++ 与 Visual Studio 2019 和 WSL(三)

    头文件 如果不小心修改了 Linux C/C++ 标准头文件,可以下面这样操作进行恢复: 项目 → 重新扫描解决方案

  6. xpath helper插件安装提示程序包无效

    参考链接:https://www.jianshu.com/p/b7d782ef81e0 刚学到爬虫,需要在Chrome浏览器安装xpath helper插件结果一直提示"程序包无效" ...

  7. VUE中v-for更新检测

    口诀: 数组变更方法,就会导致 v-for 更新,页面更新 数组非变更方法:返回新数组,就不会导致 v-for 更新,更新值检测不到可采用覆盖或者 this.$set() 数组变更方法如下: 1. a ...

  8. LeetCode:回溯算法

    回溯算法 这部分主要是学习了 labuladong 公众号中对于回溯算法的讲解 刷了些 leetcode 题,在此做一些记录,不然没几天就忘光光了 总结 概述 回溯是 DFS 中的一种技巧.回溯法采用 ...

  9. [技术博客] Django中文件的保存与访问

    [技术博客] Django中文件的保存与访问 在TextMarking项目开发中,数据库需要保存用户上传的文本文档. 原型设计:用户点击上传文本->保存文本->文本发送到后端保存为文件. ...

  10. RabbitMQ的一些理解和笔记

    在这篇博客中,简单记录一下 rabbitmq 服务器中一些基本的概念. Connection: connection 为 TCP连接,是我们的应用程序和RabbitMQ服务器真正发送和接收数据的地方. ...