题目
来自剑指Offer的第7题。
知识储备
要完成这道题,对于二叉树的前序遍历和后序遍历一定要理解到位,下方链接是我之前写的文章,请在做该题目之前阅读完以下文章。
二叉树前序、中序、后序遍历
总体思路
二叉树的前序遍历顺序是:根节点、左子树、右子树,每个子树的遍历顺序同样满足前序遍历顺序。
二叉树的中序遍历顺序是:左子树、根节点、右子树,每个子树的遍历顺序同样满足中序遍历顺序。
前序遍历的第一个节点是根节点,只要找到根节点在中序遍历中的位置,在根节点之前被访问的节点都位于左子树,在根节点之后被访问的节点都位于右子树,由此可知左子树和右子树分别有多少个节点。
由于树中的节点数量与遍历方式无关,通过中序遍历得知左子树和右子树的节点数量之后,可以根据节点数量得到前序遍历中的左子树和右子树的分界,因此可以进一步得到左子树和右子树各自的前序遍历和中序遍历,可以通过递归的方式,重建左子树和右子树,然后重建整个二叉树。
几点思考
思考1:
举个例子:
如果二叉树只有3个节点,前序:1,2,3,中序:2,1,3
前序第一个数为根节点,故根节点为1,在中序里找到根节点1,其左为左子树,右为右子树
故这棵树的形状:根节点1,左子节点2,右子节点3
思考2:
所谓“重建二叉树”,就是创建出各个节点,并让父子节点相连。最后返回整棵树的根节点。
思考3:
序列特点:
前序序列:根节点-左子树的节点们-右子树的节点们(子树的节点们又可以这样分)
中序序列:左子树的节点们-根节点-右子树的节点们(子树的节点们又可以这样分)
思考4:
如何从中序序列数组里找出根节点的位置?
选择使用Map来保存中序序列数组的index和值,来快速进行数组里值的查找
思考:为什么不用Arrays类的binarySearch方法进行二分查找?如果树太大了,多次进行二分查找效率低。
思考5:
递归时,处理的数组是不一样的(树不一样),怎么实现?
一开始处理的数组是给出的两个数组,后来变成数组的子数组,子数组的子数组,即树的子树,子树的子树。
用start、end来指明处理的是数组中的哪一个部分,随着递归而改变。前序序列数组有start、end,后序序列数组也有start、end。
思考6:
递归函数要做什么?
1.更新前序和中序序列的start、end
2.根节点连接左子树,连接右子树
3.返回根节点
代码
先根据2个前序和中序遍历的数组,重建了二叉树。再调用前序遍历方法、中序遍历方法,来遍历此二叉树。观察遍历的顺序是否和给出的两个数组的顺序相同。
import java.util.HashMap;
import java.util.Map;
public class JZO_07 {
/*07. 重建二叉树*/
/*输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。
假设输入的前序遍历和中序遍历的结果中都不含重复的数字。*/
public static void main(String[] args) {
int[] preorder = {
3,9,20,15,7};
int[] inorder = {
9,3