剑指offer-二叉树重建

183 阅读3分钟

二叉树遍历

前序遍历

先访问根节点,再访问左子节点,最后访问右子节点 10,6,4,8,14,12,16

中序遍历

先访问左子节点,再访问根节点,最后访问右子节点 4,6,8,10,12,14,16

后序遍历

先访问左子节点,再访问右子节点,最后访问根节点 4,8,6,12,16,14,10

宽度优先遍历

先访问第一层节点,再访问第二层节点,一直访问到最后一层,同一层节点中,从左到右顺序依次访问 10,6,14,4,8,12,16

题目

二叉树的前序遍历序列{1,2,4,7,3,5,6,8},中序遍历结果 (4,7,2,1,5,3,8,6),重建二叉树

分析

  1. 由前序遍历特点可以得出 前序遍历结果第一位是根节点
  2. 由中序遍历特点得出 根节点左边的元素都是左子树,右边的元素都是右子树
  3. 左右子树拆分之后,左右子树前序遍历和中序遍历的结果也符合 1,2 两个结论

步骤

  1. 查询根元素 前序遍历结果
12473568

节点 1 是根元素

  1. 分拆左右子树
47215386

查询出根元素的位置,其左边数据是左子树节点,右边部分是右子树节点 左子树中序遍历结果 :

472

右子树中序遍历结果

5386
  1. 查询左右子树对应的前序遍历结果

左子树中序遍历结果数据长度为3,那么前序遍历结果中 [1,3] 角标的数据是左子树前序遍历结果

247

右子树前序遍历结果的角标是在左子树结果之后的四个元素,右子树前序遍历结果为

3568
  1. 左右子树再继续递归处理

代码实现


public class RebuildTree {

    public static void main(String[] args) {
        int[] preArray = new int[]{1, 2, 4, 7, 3, 5, 6, 8};
        int[] inArray = new int[]{4, 7, 2, 1, 5, 3, 8, 6};
        Node node = rebuildNode(preArray, 0, preArray.length - 1, inArray, 0, inArray.length - 1);

        System.out.println(JSONObject.toJSONString(node));
    }

    /**
     * @param preArray      前序遍历结果
     * @param preStartIndex 重建二叉树前序遍历结果开始角标
     * @param preEndIndex   重建二叉树前序遍历结果结束角标
     * @param inArray       中序遍历结果
     * @param inStartIndex  重建二叉树中序遍历结果开始角标
     * @param inEndIndex    重建二叉树中序遍历结果结束角标
     * @return
     */
    private static Node rebuildNode(int[] preArray, int preStartIndex, int preEndIndex, int[] inArray, int inStartIndex, int inEndIndex) {
        if (Objects.isNull(preArray) || Objects.isNull(inArray) || preArray.length != inArray.length) {
            throw new RuntimeException("输入信息错误");
        }

        if (preStartIndex > preEndIndex) {
            return null;
        }

        int rootValue = preArray[preStartIndex];
        int rootAtInArrayIndex = inStartIndex;
        while (rootValue != inArray[rootAtInArrayIndex]) {
            rootAtInArrayIndex++;
        }

        if (rootValue != inArray[rootAtInArrayIndex]) {
            throw new RuntimeException("中序遍历结果没有查询到根节点");
        }

        Node node = new Node();
        node.setValue(rootValue);

        Node leftNode = rebuildNode(preArray, preStartIndex + 1, preStartIndex + (rootAtInArrayIndex - inStartIndex), inArray, inStartIndex, rootAtInArrayIndex - 1);
        Node rigthNode = rebuildNode(preArray, preStartIndex + (rootAtInArrayIndex - inStartIndex) + 1, preEndIndex, inArray, rootAtInArrayIndex + 1, inEndIndex);
        node.setLeft(leftNode);
        node.setRight(rigthNode);
        return node;
    }


    @Data
    private static class Node {
        private int value;
        private Node left;
        private Node right;
    }
}