剑指Offer-面试题7:重建二叉树

题目:输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树,假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如,输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历{4,7,2,1,5,3,8,6},则重建如图2.6所示的二叉树并输出它的头节点。

分析:

前序遍历:先根,再左,后右;

中序遍历:先左,再根,后右。

那么前序遍历的第一个是根,在中序遍历中找到根位置,即可确定左右子树的分布。例如:

前序:1为root    数组表示根,左,右为: pre[0],pre[0+1,0+3],pre[0+3+1,length-1]

中序:4,7,2为左子树,5,3,8,6为右子树。数组表示根,左,右: in[3],in[0,2],in[3+1,lengh-1]

设index为根结点在中序遍历中的位置,前序遍历起始位置为ps,pe,中序is,ie那么上面在前序、中序中根左右可化简为以下表示:

首先:左子树个数应为index-is(3-0)

前序表示:pre[ps],pre[ps+1,ps+index-is],pre[ps+index-is+1,pe]

后序表示:in[is],in[is,index-1],in[index+1,ie]

那么程序如下:

package main;

public class seven_createTree {
    /**
     * 定义二叉树节点,包括节点值,左右子树。
     */
    class TreeNode{
        int val;
        TreeNode left;
        TreeNode right;
    }


    public static void main(String[] args){
        seven_createTree seven_createTree=new seven_createTree();
        int[] pre={1,2,4,7,3,5,6,8};
        int[] in={4,7,2,1,5,3,8,6};
        TreeNode node = seven_createTree.reConstructBinaryTree(pre,in);
        seven_createTree.printTree(node);
    }

    /**
     * 给定二叉树的前序遍历和中序遍历,重构二叉树
     */


    /**
     *
     * @param pre 前序遍历
     * @param in 中序遍历
     * @return
     */
    public TreeNode reConstructBinaryTree(int[] pre,int[] in){
        /**
         * 输入合法性判断,不可为空,且长度至少需要一致
         */
        if(pre == null||in ==null||pre.length!=in.length){
            return null;
        }
        return construct(pre,0,pre.length-1,in,0,in.length-1);
    }

    /**
     *
     * @param pre 前序遍历
     * @param ps 前序遍历起点
     * @param pe 前序遍历终点位置
     * @param in 中序遍历
     * @param is 中序遍历起点位置
     * @param ie 中序遍历终点位置
     * @return
     */
    public TreeNode construct(int[] pre,int ps,int pe,int[] in,int is,int ie){
        if(ps>pe)return null;

        //取前序遍历的第一个数字就是根结点
        int value=pre[ps];
        //在中序遍历中寻找根节点,其前面是左子树,右边是右子树
        int index = is;
        while (index<=ie&&value!=in[index])
            index++;

        //若没有找到,则说明输入有误,抛出异常
        if(index>ie)
            throw new RuntimeException("Invalid Iuput!");

        //创建当前节点,并为根结点赋值
        TreeNode node = new TreeNode();
        node.val = value;
        //递归调用构造当前节点的左子树.此处的参数需要注意
        //当前节点的左子树的个数为index-is
        //左子树对应的前序遍历的位置在preOrder[ps+1,ps+index-is]
        //左子树对应的中序遍历的位置在inOrder[is,index-1]
        node.left = construct(pre,ps+1,ps+index-is,in,is,index-1);
        //递归调用构造当前节点的左子树.此处的参数需要注意
        //当前节点的右子树的个数为ie-index
        //右子树对应的前序遍历位置在preOrder[ps+index-is+1,pe]
        //右子树对应的中序遍历位置在inOrder[index+1,ie]
        node.right = construct(pre,ps+index-is+1,pe,in,index+1,ie);

        return node;
    }

    private void printTree(TreeNode root){
        if(root!=null){
            printTree(root.left);
            System.out.println(root.val+" ");
            printTree(root.right);
        }
    }


}

运行结果为(中序遍历):

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值