先上问题:
问题描述
最近,WYF正准备参观他的点卡工厂。WYF集团的经理氰垃圾需要帮助WYF设计参“观”路线。现在,氰垃圾知道一下几件事情:
1.WYF的点卡工厂构成一颗二叉树。
2.一共有n座工厂。
3.他需要把这颗树上的点以后序遍历的方法列出来,才能绘制地图。
还好,最近他的属下给了他先序遍历和中序遍历的数据。可是,氰垃圾最近还要帮㊎澤穻解决一些问题,没有时间。请你帮帮他,替他完成这项任务。由于氰垃圾的一些特殊的要求,WYF的参观路线将会是这棵树的后序遍历。
输入格式
第一行一个整数n,表示一共又n座工厂。
第二行n个整数,表示先序遍历。
第三行n个整数,表示中序遍历。
输出格式
输出共一行,包含n个整数,为后序遍历。
**
思路讲解:
这是一个比较简单的二叉树遍历问题,给出先序遍历,中序遍历序列,要求输出后序遍历序列。
首先需要知道什么是二叉树的先序遍历、中序遍历和后续遍历。先序遍历是先根节点D、然后左孩子L、然后右孩子R,中 序遍历LDR,后序遍历LRD。注意,这里的遍历算法对每一个节点都是这样执行,还有不明白的同学可以参考严蔚敏老师的《数据结构》关于二叉树的内容,讲得很详细。
通过对这几种遍历方法的理解,我们可以知道,先序遍历序列给出了树的跟节点,中序遍历给出了树的左叶子节点。同时,由中序遍历我们可以知道,在序列中 根节点左边的部分就是根节点的左子树,右边的部分就是根节点的右子树,然后一颗子树的后序遍历又是同样的问题!!
至此,思路就已经很清晰了:找到根节点,确定子树,然后递归或者循环。我采用的是递归的方法。还有一些边界问题,我在代码中有注释,可以结合代码看。
import java.util.*;
//二叉树,给出先序遍历和中序遍历,输出后序遍历
/*
* 基本思路:先序遍历的头元素即为整个二叉树的根节点,中序遍历的头元素是最左叶子节点
* 按照中序遍历的算法,当遇到根节点时,即表示树的以便已经遍历完成,即
* 中序遍历序列中,在整树根节点的左边的元素就在根节点左边,右边的树就在右边
* 于是,这个问题就被分解为;两个子问题了。每一次确定树的左右之后,就得到了左右两颗子树
* 而每颗子树的排列又是一样的问题,可以考虑递归算法
* 值得主义的是,子树的边界是什么?
* 二叉树,每一个根节点都有两个子节点,所以,子树的边界就是2
* 即当最后一个子树只有两个元素时,递归就可以结束了
* 按照先序排列的算法,既可以确定这两个元素的位置
*
*
* 还有一个值得思考的问题是,如果根节点的左孩子和他一样呢?
* 或者有孩子节点和他值相同呢?那么上面的方法就会出问题。
* 这时候如何确定中序遍历序列是否完整遍历左树?
*
* 一个可行的方法是在前面的基础上,比较先序遍历的子序列Arrays.copyOfRange(fst, 1, i+1)
* 是否和中序遍历的Arrays.copyOfRange(mid, 0, i)相等,
* 如果相等,证明这就是根节点,否则继续向后遍历
* */
public class Tree {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
int n=sc.nextInt();
int[] fst=new int [n];
int[] mid= new int [n];
for(int i=0;i<n;i++) {
fst[i]= sc.nextInt();
}
for(int j=0; j<n;j++) {
mid[j]= sc.nextInt();
}
sc.close();
TreeSort(fst, mid);
/*
* 我的代码老是不通过
* 爱报bug
* 你说啷个搞嘛
* 小错误好难得纠
* 憨了
* 逼着自己的大晚上写题
* 呜呜呜
* */
}
public static void TreeSort(int[] fst,int [] mid) {
if(fst.length != mid.length) {
return;
}
if(mid.length <= 2) {
for(int i=0; i< mid.length; i++) {
System.out.print(mid[i]+" ");
}
return;
}
// else {
// System.out.print(mid[0]+" ");
// }
// int [] temp2, temp1;
//左子树后序遍历输出
for(int i=0;i<mid.length; i++) {
int[] temp2=Arrays.copyOfRange(mid, 0, i);
int [] temp1= Arrays.copyOfRange(fst, 1, i+1);
Arrays.sort(temp1);
Arrays.sort(temp2);
//确定中序遍历序列中是否到达二叉树的根节点
if(mid[i]== fst[0] && equl(temp1,temp2)) {
/*
* 现在的问题是程序没有键入这个if结构
* 也就是if的判断条件不对
* 我怀疑是那个equals方法不对,不能正确比较两个数组是否相等
* 其余暂时没有发现问题
* 03/11
* */
TreeSort(Arrays.copyOfRange(fst, 1, i+1), Arrays.copyOfRange(mid, 0, i));//左树
TreeSort(Arrays.copyOfRange(fst, i+1, fst.length), Arrays.copyOfRange(mid, i+1, mid.length));
System.out.print(fst[0]+" ");
break;
}
}
// System.out.print(fst[0]);
//
}//TreeSort()
//写一个判断子树是否相等的函数,返回boolean值
public static boolean equl(int[] s1,int[] s2) {
if(s1.length != s2.length) {
return false;
}
for(int i=0; i<s1.length;i++) {
if(s1[i]!= s2[i]) {
return false;
}
}
return true;
}
}
但是这个算法有个缺陷,就是时间复杂度太高,主要是equl()方法造成的,我没有想到更好的办法,使用数组的equals()方法不行。
临时写的一篇博客,也许漏洞百出,欢迎指正!
**