题目:输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

    首先通过一个例子看看前序遍历和中序遍历的特点,如下二叉树
    重建二叉树 - 图1
    它的前序遍历和中序遍历的结果为
    重建二叉树 - 图2
    我们分析一下前序遍历和中序遍历的结构
    重建二叉树 - 图3
    我们的思路是首先根据前序遍历找到根节点的值(第一个),接着根据找到的根节点的值,在中序遍历中找到根节点的位置,在中序遍历中根节点左边的值是它的左子树的中序遍历,右边是它的右子树的中序遍历,并且进一步可以得到左右子树的长度,根据左右子树的长度,可以在前序遍历中找到左子树的前序遍历和右子树的前序遍历,然后重复上面的过程,又可以找到左右子树的根节点的值以及相应的左右子树,以此类推,即可重建二叉树。

    完整代码如下:

    1. public class Test {
    2. // 二叉树的定义
    3. private static class BinaryTree {
    4. int value;
    5. BinaryTree left;
    6. BinaryTree right;
    7. public BinaryTree(int value) {
    8. this.value = value;
    9. }
    10. }
    11. // preorder 前序遍历的数组
    12. // inorder 中序遍历的数组
    13. public static BinaryTree constructBinaryTree(int[] preorder, int[] inorder) throws Exception{
    14. if (preorder == null || inorder == null) {
    15. throw new Exception("preorder or inorder is null");
    16. }
    17. return helpContructBinaryTree(preorder, 0, preorder.length - 1,
    18. inorder, 0, inorder.length - 1);
    19. }
    20. // 根据前序遍历数组和中序遍历数组获得根节点
    21. private static BinaryTree helpContructBinaryTree(int[] preorder, int preStart, int preEnd,
    22. int[] inorder, int inStart, int inEnd) throws Exception{
    23. // 前序遍历的第一个值就是根节点
    24. BinaryTree root = new BinaryTree(preorder[preStart]);
    25. // 如果只有数组只有一个值
    26. if (preStart == preEnd) {
    27. if (inStart == inEnd && preorder[preStart] == inorder[inStart]) {
    28. return root;
    29. } else {
    30. throw new Exception("wrong input");
    31. }
    32. }
    33. // 获得中序遍历根节点的位置
    34. int inOrderRoot = inStart;
    35. for (; inOrderRoot <= inEnd; inOrderRoot++) {
    36. if (inorder[inOrderRoot] == root.value) {
    37. break;
    38. }
    39. }
    40. // 如果在中序遍历中没有找到根节点 则输入的数组有错误
    41. if (inOrderRoot > inEnd) {
    42. throw new Exception("wrong input");
    43. }
    44. // 左右子树的长度
    45. int leftLength = inOrderRoot - inStart;
    46. int rightLength = inEnd - inOrderRoot;
    47. if (leftLength > 0) {
    48. // 根据左子树的前序遍历和中序遍历获得左子树的根节点
    49. // [preStart + 1, preStart + leftLength] 左子树的前序遍历的范围
    50. // [inStart, inOrderRoot - 1] 左子树的中序遍历的范围
    51. root.left = helpContructBinaryTree(preorder, preStart + 1, preStart + leftLength,
    52. inorder, inStart, inOrderRoot - 1);
    53. }
    54. if (rightLength > 0) {
    55. // 同左子树
    56. root.right = helpContructBinaryTree(preorder, preStart + leftLength + 1, preEnd,
    57. inorder, inOrderRoot + 1, inEnd);
    58. }
    59. return root;
    60. }
    61. }