输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
或者再给出后序遍历序列{7,4,2,5,8,6,3,1},让你通过后序和中序重建二叉树。其实中序后序重建二叉树和前序中序重建二叉树原理相同,所以我们先来看前序中序重建二叉树。
重建结构为
1
/ \
2 3
/ / \
4 5 6
\ /
7 8
前序中第一个元素总是二叉树的根节点,拿到根节点后遍历中序,寻找中序中的根节点,找到后根节点。
左边的元素为根节点的左子树,右边的元素为右子树,例如上题中的前序preOrder = {1,2,4,7,3,5,6,8}和中序为inOrder =
{4,7,2,1,5,3,8,6} 。
估计看着不方便,所以把代码中的重要注释贴在这里
二叉树数据结构定义:
class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val){
this.val = val;
}
}
利用前序和中序重建二叉树:
代码中的重要注释也写在前面,如果想测试最终重建成功与否,可以将重建的二叉树按层打印出来,按层打印二叉树可以看这篇博客https://mp.csdn.net/postedit/89322538
public static TreeNode reConstructBinaryTree(int [] pre,int [] in) {
if (pre == null || in == null || pre.length != in.length || pre.length < 1) {
return null;
}
//调用递归
TreeNode root = reConstructBinaryTree(pre, 0, pre.length-1, in, 0, in.length-1);
return root;
}
private static TreeNode reConstructBinaryTree(int[] pre, int startPre, int endPre, int[] in, int startIn, int endIn) {
if (startPre > endPre || startIn > endIn) {
return null;
}
// 根节点为前序数组的第一个元素
TreeNode root = new TreeNode(pre[startPre]);
for (int i = 0; i <= endIn; i++) {
//根据前序遍历得到的根结点在中序遍历中查找根结点的下标i
if (pre[startPre] == in[i]) {
/*
* 接着进行递归,因为得到中序的根节点后,中序数组根节点左边的元素为左子树,右边的元素为右子树
* 计算左右子树的起始和结束下标,然后继续进行递归
* */
/*计算左树子节点其实结束下标
* 前序起始位置startPre = 原来的前序的startPre后移一位,也就是 startPre = startPre + 1
* 前序结束下标endPre = 前序起始位置 + 左子树元素的长度,左子树长度=查出的中序根节点下标值减去中序的初始下标,
* 也就是左子树长度 = i - startIn,综合起来就是前序结束下标 enPre = startPre + i - startIn。
*
* 中序起始位置startIn = startIn ,保持不变
* 前序结束下标endIn = 查出来的中序根节点下标值 - 1,即endIn = i-1。
* */
root.left = reConstructBinaryTree(pre,startPre+1,startPre+i-startIn,in,startIn,i-1);
/*
* 前序起始位置其实就是左子树前序结束下标+1,因为总的前序被分为两部分,一部分为左子树的前序,
* 一部分为右子树的前序,既然左子树的前序结束下标为endPre = startPre+i-startIn,
* 那么右子树的起始下标startIn=startPre+i-startIn+1
* 右子树的前序结束下标endPre = endPre
*
* 右子树的中序起始下标startIn同理,左右子树的中序也将总的中序分为两部分,而且处于查出来的中序根节点下标值的两边,
* 即左子树结束下标为i-1,右子树起始下标为i+1,而右子树的结束下标也自然而然是endIn。
* */
root.right = reConstructBinaryTree(pre,startPre+i-startIn+1,endPre,in,i+1,endIn);
// 在中序中找到根节点直接退出循环
break;
}
}
return root;
}
前面实现了前序中序重建二叉树,那么可以以此类推后序中序重建二叉树。以下为实现代码
public static TreeNode reConstructBinaryTree1(int [] post,int [] in) {
if (post == null || in == null || post.length != in.length || post.length < 1) {
return null;
}
//调用递归
TreeNode root = reConstructBinaryTree1(post, 0, post.length-1, in, 0, in.length-1);
return root;
}
private static TreeNode reConstructBinaryTree1(int[] post, int startPost, int endPost, int[] in, int startIn, int endIn) {
if (startPost > startPost || startIn > endIn) {
return null;
}
// 根节点为前序数组的第一个元素
TreeNode root = new TreeNode(post[endPost]);
for (int i = endPost; i >= 0; i--) {
//根据后序遍历得到的根结点在中序遍历中查找根结点的下标i
if (post[endPost] == in[i]) {
root.left = reConstructBinaryTree1(post,startPost,startPost+i-startIn-1,in,startIn,i-1);
root.right = reConstructBinaryTree1(post,startPost+i-startIn,endPost-1,in,i+1,endIn);
break;
}
}
return root;
}