本题代码已上传到:gitbub
题目
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建出图2.6所示的二叉树并输出它的头结点。
题目分析
在数据结构里讨论树的时候基本都是讨论二叉树,我们知道二叉树是一种特殊的树,其每个节点的子节点都不超过2个,而二叉树又可以引申出二叉搜索树,平衡二叉树(AVL树),红黑树等概念,关于树的参考。
此题目考察的是对二叉树的基本数据结构理解,及二叉树的遍历的理解。二叉树的遍历要掌握的主要是前/中/后序的遍历:
前序遍历:先访问根节点,再访问做节点,最后访问右节点;
中序遍历:先访问左节点,再访问根节点,最后访问右节点;
后序遍历:先访问左节点,再访问右节点,最后访问根节点;
层序遍历:从根开始,一层一层的遍历二叉树。(不常见,但是要知道概念)。
在二叉树的前序遍历中,第一个数字总是树的根节点。在中序遍历中,树的根节点在序列的中间,左子树的节点的值位于根节点的左边,右子树节点的值位于根节点值的右边。
所以重点就是:
根据前序序列找到根节点,然后在中序序列中找到根结点的位置,由此可以找到左子树的节点的个数和右子树节点的个数,然后在前序序列中找到左子树的根节点,再到中序序列中找到左子树的左子树和右子树。依次递归。
核心代码实现
/**
* 根据前序和中序序列重建二叉树
*
* @param preorder 前序序列
* @param inorder 中序序列
* @return 二叉树
*/
private static BinaryTreeNode construct(int[] preorder, int[] inorder) {
if (preorder == null || inorder == null || preorder.length != inorder.length || preorder.length <= 0) {
throw new RuntimeException("Invalid input.");
}
return constructCode(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1);
}
/**
* 根据前序和中序序列重建二叉树
*
* @param preorder 前序序列
* @param ps 前序遍历开始索引
* @param pe 前序遍历结束索引
* @param inorder 中序序列
* @param is 中序遍历开始索引
* @param ie 中序遍历结束索引
* @return 二叉树
*/
private static BinaryTreeNode constructCode(int[] preorder, int ps, int pe, int[] inorder, int is, int ie) {
if (ps > pe || is > ie) {
return null;
}
BinaryTreeNode node = new BinaryTreeNode();
node.val = preorder[ps];
if (ps == pe) {
if (is == ie && preorder[ps] == inorder[is]) {
return node;
} else {
throw new RuntimeException("Invalid input.");
}
}
int idx = is;
while (idx < ie && inorder[idx] != node.val) {
++idx;
}
if (idx == ie && inorder[idx] != node.val) {
throw new RuntimeException("Invalid input.");
}
int leftLength = idx - is;
if (leftLength > 0) {
node.left = constructCode(preorder, ps + 1, ps + leftLength, inorder, is, idx - 1);
}
if (leftLength < pe - ps) {
node.right = constructCode(preorder, ps + leftLength + 1, pe, inorder, idx + 1, ie);
}
return node;
}
测试用例
public static void main(String[] args) {
//普通二叉树
int[] preorder = {1, 2, 4, 7, 3, 5, 6, 8};
int[] inorder = {4, 7, 2, 1, 5, 3, 8, 6};
BinaryTreeNode root = construct(preorder, inorder);
postorderPrint(root); //后序打印
//所有节点都没有右节点
// int[] preorder = {1, 2, 3, 4, 5};
// int[] inorder = {5, 4, 3, 2, 1};
// BinaryTreeNode root = construct(preorder, inorder);
// postorderPrint(root); //后序打印
//所有节点都没有左节点
// int[] preorder = {1, 2, 3, 4, 5};
// int[] inorder = {1, 2, 3, 4, 5};
// BinaryTreeNode root = construct(preorder, inorder);
// postorderPrint(root); //后序打印
//只有一个节点
// int[] preorder = {1};
// int[] inorder = {1};
// BinaryTreeNode root = construct(preorder, inorder);
// postorderPrint(root); //后序打印
// 完全二叉树
// int[] preorder = {1, 2, 4, 5, 3, 6, 7};
// int[] inorder = {4, 2, 5, 1, 6, 3, 7};
// BinaryTreeNode root = construct(preorder, inorder);
// postorderPrint(root); //后序打印
//空指针
// BinaryTreeNode root = construct(null, null);
// postorderPrint(root); //后序打印
//序列不匹配
// int[] preorder = {1, 2, 4, 5, 3, 6, 7};
// int[] inorder = {4, 2, 8, 1, 6, 3, 7};
// BinaryTreeNode root = construct(preorder, inorder);
// postorderPrint(root); //后序打印
}