重建二叉树

来源:互联网 发布:chrome 无法调用 java 编辑:程序博客网 时间:2024/06/04 19:16

以下题目内容来自《剑指Offer》
题目描述:输入某二叉树的前序遍历和中序遍历的结果,请重新构造出该二叉树。假设输入的前序遍历和中序遍历的结果中不包含重复的数字。例如输入的前序遍历序列为{1,2,4,7,3,5,6,8}和中序遍历为{4,7,2,1,5,3,6,8},则重建出二叉树并输出它的头结点。
在二叉树的前序遍历序列中,第一个数字总是树的根节点的值。但在中序遍历中,根节点的值在序列的中间,左子树的结点的值位于根节点的值的左边,而右子树的结点的值位于根节点的右边。因此我们需要扫描中序遍历序列,才能找到根节点的值。
如图所示,前序遍历序列的第一个数字1就是根节点的值。扫描中序遍历序列,就能确定根节点的值的位置。根据中序遍历的特点,在根节点的值1前面3个数字都是左子树结点的值,位于1后面的数字都是右子树结点的值。
这里写图片描述
由于中序遍历序列中,有3个数字是左子树结点的值,因此左子树总共有3个左子结点。同样,在前序遍历的序列中,根节点后面的3个数字就是3个左子树结点的值,再后面的所有数字都是右子树结点的值。这样我们就在前序遍历和中序遍历两个序列中,分别找到了左右子树对应的子序列。
这里写图片描述
既然我们已经分别找到了左、右子树的前序遍历序列和中序遍历序列,我们可以用同样的方法分别去构建左右子树。也就是说,接下来的事情可以用递归的方法去完成。
书中只给出了思路和C++代码,根据这个思路,我用java实现,代码如下:

package com.sOffer;/** * 根据前序遍历和中序遍历重建二叉树 * @author lhqj * */class TreeNode{    int val;    TreeNode leftNode;    TreeNode rightNode;    public TreeNode(int val){        this.val = val;    }}public class Main2 {    public static void main(String[] args) {         int[] preOrder={1,2,4,7,3,5,6,8};           int[] inOrder={4,7,2,1,5,3,8,6};         System.out.println(Construct(preOrder,inOrder).val);    }    private static TreeNode Construct(int[] preOrder,int[]inOrder){        if(preOrder == null || inOrder == null)            return null;        return ConstructCore(preOrder,0,preOrder.length - 1,inOrder,0,inOrder.length - 1);    }    private static TreeNode ConstructCore(int[]preOrder,int sPreIndex,int ePreIndex,int[]inOrder,int sInIndex,int eInIndex){        //前序遍历序列的第一个数字就是根节点的值        int rootVal = preOrder[sPreIndex];        TreeNode root = new TreeNode(rootVal);        root.leftNode  = null;        root.rightNode = null;        if(sPreIndex == ePreIndex){//只有一个元素            if(sInIndex == eInIndex && preOrder[sPreIndex] == inOrder[sInIndex]){//                return root;            }else{                try {                    throw new Exception ();                } catch (Exception e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }            }        }        //在中序遍历中找到根节点的值,再分为左子树和右子树        int rootIndex = sInIndex;        while(rootIndex <= eInIndex && inOrder[rootIndex] != rootVal){            ++rootIndex;        }        //中序最后一个就是根节点,那么这棵树是没有右子树的,那输入的参数有问题        if(rootIndex == eInIndex && inOrder[rootIndex]!=rootVal){            try {                throw new Exception ();            } catch (Exception e) {                // TODO Auto-generated catch block                e.printStackTrace();            }        }        int  leftLen = rootIndex - sInIndex;//左子树的节点个数        int leftPreOrderEndIndex = sPreIndex + leftLen;//对应前序序列中的左子树节点位置        if(leftLen > 0){            //构建左子树            root.leftNode = ConstructCore(preOrder, sPreIndex + 1, leftPreOrderEndIndex,                     inOrder, sInIndex, rootIndex - 1);        }        if(leftLen < ePreIndex - sPreIndex){//右子树还有            //构建右子树            root.rightNode = ConstructCore(preOrder, leftPreOrderEndIndex + 1,                     ePreIndex, inOrder, rootIndex + 1, eInIndex);        }        return root;    }}

通过递归调用,通过前序遍历序列得知当前子树的根节点,再根据中序遍历得知以当前根节点为根的子树的左右子树中 的节点,一步一步的从子节点到子数再到左(右)子树。

0 0
原创粉丝点击