问题描述
本题需要根据二叉树的前序遍历序列和中序遍历序列重构二叉树,我用Java写了两种实现,但个人觉得第一种实现更为简洁。
实现一
public class BinaryTreeConstruction1 {
//根据二叉树前序遍历及中序遍历结果重构二叉树
private static class BinaryTreeNode{
//二叉树节点
int value;
BinaryTreeNode leftNode;
BinaryTreeNode rightNode;
}
public static BinaryTreeNode binaryTreeConstruct(int[] preorder, int[] inorder, int length){
//输入合法性验证
if (preorder == null || inorder == null || length <= 0 || preorder.length != inorder.length){
throw new IllegalArgumentException("Invalid Input");
}
return construct(preorder, inorder,
0, preorder.length - 1, 0, inorder.length - 1);
}
private static BinaryTreeNode construct(int[] preorder, int[] inorder, int startPre, int endPre,
int startIn, int endIn){
//根据前序遍历序列第一位初始化根节点
BinaryTreeNode rootNode = new BinaryTreeNode();
rootNode.value = preorder[startPre];
rootNode.leftNode = null;
rootNode.rightNode = null;
//递归终止条件
if (startPre == endPre){
if (startIn == endIn && preorder[startPre] == inorder[startIn])
return rootNode;
else
throw new IllegalArgumentException("Invalid Input");
}
//找到中序遍历序列中根节点位置
int rootInIndex = startIn;
while(rootInIndex <= endIn && inorder[rootInIndex] != preorder[startPre])
rootInIndex++;
//验证是否找到,找不到则报错
if (rootInIndex == -1)
throw new IllegalArgumentException("Invalid Input");
//同时在两个序列中区分左右子树,并递归重构左右子树
if (rootInIndex > startIn)
rootNode.leftNode = construct(preorder, inorder,
startPre + 1, rootInIndex - startIn + startPre, startIn, rootInIndex - 1);
if (rootInIndex < endIn)
rootNode.rightNode = construct(preorder, inorder,
rootInIndex - startIn + startPre + 1, endPre, rootInIndex + 1, endIn);
//回溯
return rootNode;
}
private static void printPreorder(BinaryTreeNode rootNode){
//打印重构二叉树的前序遍历序列
if (rootNode == null)
return;
System.out.printf("%d\t", rootNode.value);
printPreorder(rootNode.leftNode);
printPreorder(rootNode.rightNode);
}
private static void printInorder(BinaryTreeNode rootNode){
//打印重构二叉树的中序遍历序列
if (rootNode == null)
return;
printInorder(rootNode.leftNode);
System.out.printf("%d\t", rootNode.value);
printInorder(rootNode.rightNode);
}
//测试用例
public static void main(String[] args){
int[] pre = {1, 2, 4, 7, 3, 5, 6, 8};
int[] in = {4, 7, 2, 1, 5, 3, 8, 6};
BinaryTreeConstruction1 construction = new BinaryTreeConstruction1();
printPreorder(BinaryTreeConstruction1.binaryTreeConstruct(pre, in, 8));
System.out.println();
printInorder(BinaryTreeConstruction1.binaryTreeConstruct(pre, in, 8));
}
}
实现二
import java.util.Arrays;
public class BinaryTreeConstruction2 {
//根据二叉树前序遍历及中序遍历结果重构二叉树
private static class BinaryTreeNode{
int value;
BinaryTreeNode leftNode;
BinaryTreeNode rightNode;
}
public static BinaryTreeNode binaryTreeConstruct(int[] preorder, int[] inorder, int length){
if (preorder == null || inorder == null || length <= 0)
return null;
if (preorder.length != inorder.length)
throw new IllegalArgumentException("Invalid Input");
return constructCore(preorder, inorder);
}
private static BinaryTreeNode constructCore(int[] preorder, int[] inorder){
//找到中序遍历结果中根节点的位置,区分左右子树,再分别寻找左右子树的根节点
BinaryTreeNode rootNode = new BinaryTreeNode();
rootNode.value = preorder[0];
int length = preorder.length;
//递归终止条件
if (length == 1) {
if (preorder[0] == inorder[0])
return rootNode;
else
throw new IllegalArgumentException("Invalid Input");
}
//找到中序遍历结果中根节点位置
int rootIndex = -1;
for (int i = 0; i < length; i++){
if (preorder[0] == inorder[i])
rootIndex = i;
}
//没找到则抛出异常
if (rootIndex == -1)
throw new IllegalArgumentException("Invalid Input");
//递归构造根节点左右子树
if (rootIndex > 0){
//区分中序遍历结果中的左右子树
int[] leftInorder = Arrays.copyOfRange(inorder,0, rootIndex);
int[] leftPreorder = Arrays.copyOfRange(preorder, 1, rootIndex + 1);
rootNode.leftNode = constructCore(leftPreorder, leftInorder);
}
if (length - rootIndex - 1 > 0){
//区分前序遍历结果中的左右子树(根据左右子树元素个数)
int[] rightInorder = Arrays.copyOfRange(inorder, rootIndex + 1, length);
int[] rightPreorder = Arrays.copyOfRange(preorder, rootIndex + 1, length);
rootNode.rightNode = constructCore(rightPreorder, rightInorder);
}
return rootNode;
}
private static void printPreorder(BinaryTreeNode rootNode){
if (rootNode == null)
return;
System.out.printf("%d\t", rootNode.value);
printPreorder(rootNode.leftNode);
printPreorder(rootNode.rightNode);
}
//测试用例
public static void main(String[] args){
int[] pre = {1, 2, 4, 7, 3, 5, 6, 8};
int[] in = {4, 7, 2, 1, 5, 3, 8, 6};
printPreorder(BinaryTreeConstruction2.binaryTreeConstruct(pre, in, 8));
}
}