何为先序遍历??
先序遍历(DLR)(根左右)
先序遍历也叫做先根遍历、前序遍历,可记做根左右。
先序遍历首先访问根结点然后遍历左子树,最后遍历右子树。在遍历左、右子树时,仍然先访问根结点,然后遍历左子树,最后遍历右子树。
若二叉树为空则结束返回,否则:
(1)访问根结点。
(2)前序遍历左子树。
(3)前序遍历右子树 。
需要注意的是:遍历左右子树时仍然采用前序遍历方法。
如图所示二叉树
前序遍历,也叫先根遍历,遍历的顺序是,根,左子树,右子树
遍历结果:ABDECF
中序遍历,也叫中根遍历,顺序是 左子树,根,右子树(左根右)
遍历结果:DBEAFC
后序遍历,也叫后根遍历,遍历顺序,左子树,右子树,根(左右根)
遍历结果:DEBFCA
好,明白概念了,我们来做个题吧!
洛谷——P1030 求先序排列
题目描述
给出一棵二叉树的中序与后序排列。求出它的先序排列。(约定树结点用不同的大写字母表示,长度<=8)。
输入输出格式
输入格式:
2行,均为大写字母组成的字符串,表示一棵二叉树的中序与后序排列。
输出格式:
1行,表示一棵二叉树的先序。
输入输出样例
输入样例#1:
BADC BDCA
输出样例#1:
ABCD
思路:
对于一棵树,我们可以知道他的后续遍历的最后一项一定是这棵树的根。
这样我们在拿到一棵树的中序遍历和这棵树的后序遍历以后,我们先找到这棵树的根节点;
然后再对这棵树的中续遍历扫一遍,确定下来这个根节点在中序遍历的位置,这样,在这棵树的根节点两边的就分别是这个根节点的左右子树
然后我们就把这整棵树转化成两颗子树的问题了!
这样对于这个题,我们就采取分治的方法进行求解!
注意:
本题使用gets时全部wa掉,改成scanf就全都对了!
同时注意if(d[R]<r) dfs(d[R]+1,r,R-r+d[R],R-1);里面为r!
在这里我们就来看看scanf和gets的区别吧!
首先:scanf可以接受多个字符串,而gets只可以接受一个字符串
其次:scanf不能读入带空格的字符串,gets可以读入带空格的字符串
最后:scanf()不能接受长度为0的字符串,会自动忽略开头的所有空格,并且以空格、换行符、回车结束输入
。而gets()能接受长度为0的字符串,不会自动忽略开头的所有空格或回车,并以回车结束。
代码:
#include<vector> #include<stdio.h> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define N 100000 #define maxn 123456 using namespace std; char a[N],b[N]; int c[N],d[N]; void dfs(int l,int r,int L,int R) { printf("%c",b[R]); if(d[R]>l) dfs(l,d[R]-1,L,d[R]-l+L-1);//说明他有左子树,那么对她的左子树进行查找 //对一棵树来说,它的左子树的最左端一定是L,最右端就是 //它的根所在的地方(在中序排序中)+减去中序排序的左端点——这是求出了他的左子树的长度 //那他的在后续排序中的最右端是在后续排序的左端+他的左子树的长度 if(d[R]<r) dfs(d[R]+1,r,R-r+d[R],R-1);//说明它具有右子树,那么对他的右子树进行查找。 // 对一棵树来说,他的右子树在后续遍历中左端点的的位置为:R-r+d[R] //r-d[R]是求出了这棵树的右子树的长度,那他的左端点为当前的右端点减去右子树的长度 } int main() { /*gets(a);//这棵树的中序排序 gets(b);//这棵树的后序排序 */ scanf("%s",a); scanf("%s",b); int l=strlen(a);//对于一棵树来说:他的中序排序和它的后续排序的长度是相同的,所以在这里我们只要求他中序排序的长度就好了! for(int i=0;i<l;i++) c[a[i]]=i;//储存中序排序的每个点在中序排序中的位置 for(int i=0;i<l;i++ ) d[i]=c[b[i]];//储存后序遍历的每个点在中序遍历中的位置; dfs(0,l-1,0,l-1);//同时在中序遍历和后序便利中进行查找(第一个1~n是中序遍历要进行查找的位置,第二个是后续遍历要查找的位置) return 0; }