java-剑指offer-7重建二叉树

 

package com.areio.offer;

public class TreeNode {
    //每一个结点要包含左指针,右指针,当前结点的值
    int val;
    TreeNode left = null;
    TreeNode right = null;
    //把左右节点设为null,构造新结点时不用自己设置
     public TreeNode(int val){
         this.val=val;
     }
}

 

package com.areio.offer;

import static com.areio.offer._7A_TreeVisit.preOrder1;

/*
* 题目:输入某二叉树的前序和中序遍历,重构二叉树(假设输入的前序遍历和中序遍历未含重复数字)。
* 例如前序遍历{1,2,4,7,3,5,6,8},{4,7,2,1,5,3,8,6},其二叉树为
*                1
*          2           3
*       4          5       6
*         7             8
*
*
* 测试用例:
* 1、特殊输入:前序中序矛盾——构不成二叉树;二叉树根节点为null
* 2、特殊二叉树:只有左子树;只有右子树;只有一个结点
* 3、普通二叉树:完全二叉树;不完全二叉树
*
* 思路:
* 1、根据前序遍历得到根节点root,构建根
* 2、根据root去中序遍历得到其左子树和右子树,构建左右子树
* 3、左右子树的构建与1、2一样,可用递归调用当前函数
*
* */
public class _7_RebuildTree {
    /*
    * preOder:前序遍历
    * inOrder:中序遍历
    * length:元素个数
    * */
    public static TreeNode constructor(int[] preOrder,int[] inOrder,int length){
        if (preOrder==null||inOrder==null||length<=0) return null;
        return rebuildTree(preOrder,0,preOrder.length-1,inOrder,0,inOrder.length-1);
    }
    /*
      构建一棵树,该函数需要被子树复用,下次子树要构建自己,需要将自己孩子的范围传进来

    * startPreOrder:当前子树的前序遍历的起始索引
    * endPreOrder:当前子树的前序遍历的终止索引
    * */
    public static TreeNode rebuildTree(int[] preOrder,int startPreOrder,int endPreOrder,int[] inOrder,int startInOrder,int endInOrder){

        //1、从前序遍历中找到根节点,并构建该结点
        int rootVal=preOrder[startPreOrder];
        TreeNode root=new TreeNode(rootVal);

        //2、从中序遍历找到该结点根结点
        int rootIndex=startInOrder;
        while (rootIndex<=endInOrder && inOrder[rootIndex]!=rootVal){//要么是因为到最后一个元素了,要么是找到了根了才会退出循环
            rootIndex++;
        }
        //是否在中序遍历有找到根节点
        //因为到了最后一个元素退出的循环——中序遍历中没有根节点
        if (rootIndex==endInOrder+1){
            try {
                throw  new Exception("前序中序遍历不匹配");
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
        //到这里说明是在中序遍历里找到了根了
        //3、确定根结点的左右子树
        //计算根左右子树的前序遍历的起止位置,在中序遍历的起止位置
        int leftTreeLength=rootIndex-startInOrder;//左子树长度
        int rightTreeLength=endInOrder-rootIndex;//右子树长度

        //子树在前序遍历的起始位置
        int leftPreOrderStart=startPreOrder+1;
        //子树在前序遍历的终止位置
        int leftPreOrderEnd=startPreOrder+leftTreeLength;

        //4、构建左子树,传入左子树在前序遍历的起止位置,在中序遍历的起止位置
        if (leftTreeLength>0) {//当左子树右子树为空则自己结束递归
            root.left=rebuildTree(preOrder, leftPreOrderStart, leftPreOrderEnd,inOrder,startInOrder,rootIndex-1);
        }
        //5、构建右子树
        if (rightTreeLength>0){
            root.right=rebuildTree(preOrder,leftPreOrderEnd+1,endPreOrder,inOrder,rootIndex+1,endInOrder);
        }

        //如果只有一个结点,则直接返回根结点
        return root;
    }

    public static void main(String[] args) {
        //不完全二叉树
        int[] preOrder = new int[] {1,2,4,7,3,5,6,8};
        int[] inOrder = new int[] {4,7,2,1,5,3,8,6};
        //构不成二叉树
//        int[] preOrder = new int[] {1,2,4,7,3,5,6,8};
//        int[] inOrder = new int[] {8,8,2,1,5,3,8,6};
        //null
//        int[] preOrder = new int[] {};
//        int[] inOrder = new int[] {};
        //只有左子树
//        int[] preOrder = new int[] {1,2,4,7};
//        int[] inOrder = new int[] {7,4,2,1};
        TreeNode root = constructor(preOrder, inOrder, preOrder.length);


        System.out.println("输入的前序遍历:");
        for (int i:preOrder){
            System.out.print(i+" ");
        }
        System.out.println();
        //打印出该树的前序遍历验证是否与输入的一样
        System.out.println("重构树的前序遍历:");
        preOrder1(root);

    }
}

前序遍历的方法查看:二叉树的遍历(前中后层次)icon-default.png?t=LA92https://mp.csdn.net/mp_blog/creation/editor/122100011

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值