根据前序和中序遍历重建二叉树
热身题目
已知二叉树先序遍历序列是A-B-C-D-E-F-G,中序遍历序列是C-B-D-A-E-G-F。由这两个序列可唯一确定一颗二叉树。
分析
从先序遍历序列第一个节点可知二叉树根节点是A。
由节点A在中序遍历序列里位置可知该根点左子树包含节点 B-C-D,右子树包含节点 E-G-F。
由先序序列片段 B-C-D可知,B是A左子树根节点,再结合中序序列片段 C-B-D可知,C和D分别是B的左右子节点。
由先序序列片段E-F-G可知,E是A的右子节点,结合中序序列片段E-F-G可知,G和F均是E的右子树节点。
再由先序序列片段F-G和中序序列片段G-F可知,F是E的右子节点,并且G是F的左子结点。
正题
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。 例如输入前序遍历序列{1, 2, 4, 7, 3, 5, 6, 8}和中序遍历序列{4, 7, 2, 1, 5, 3, 8, 6},则重建出其二叉树并输出它的头结点。
思路
前序遍历第一个值就是根结点的值,根据该值在中序遍历的位置,可以轻松找出该根结点左右子树的前序遍历和中序遍历,之后又可以用同样方法构建左右子树,所以该题可以采用递归的方法完成。
刚开始思考的时候,想的是构建一个遍历函数,输入为前序和中序遍历的数组,输出为根结点。但是这样的话每次都需要构建子树的数组,非常麻烦。
之后想到,该函数的输入不一定要用数组,因为最初的前序和中序遍历数组已经有了,就直接用该数组的下标来表示子树的数组即可。
即构建函数 construct(int[] pre, int[] in, int pStart, int pEnd, int iStart, int iEnd) ,pre和in始终用最初前序遍历和中序遍历的数组代入,pStart、pEnd代表当前树的前序数组开始和结束位置,iStart、iEnd代表中序数组开始和结束位置。
测试用例
- 正常二叉树
- 左斜树
- 右斜树
- 单个结点
- 数组为空
- 前序与中序不匹配
Java代码
1 | public class ConstructBinaryTree { |
测试部分代码,如下:
1 | public class ConstructBinaryTree { |
总结
- 在递归问题中,代码可以用下标表示的就用下标表示,不用重新构建新的数组。
- 数组为空与数组为null不是一回事。