根据先序遍历与中序遍历构建二叉树

题目(剑指offer page55):

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

例如:输入前序遍历序列 {1,2,4,7,3,5,6,8 }和中序遍历序列{4,72,1,5,3,6,8}

那么构建之后的二叉树为: 


思路:

在二叉树的先序遍历中,第一个数字总是树的根节点的值。但在中序遍历中,根节点的值在序列中间,左子树的节点的值位于根节点左边,右子树的节点的值位于根节点的右边。因此,我们需要遍历中序遍历序列,找到根节点。那么,中序遍历序列中根节点左边的序列是二叉树的左子树的中序遍历序列(假设序列长度为M),右边的是二叉树右子树的中序遍历序列(假设序列长度为N)。同样,在先序遍历序列中,根节点后面的M个值是二叉树的左子树的先序遍历序列,再后面的N个值是二叉树右子树的先序遍历序列。这样我们就得到了二叉树的根以及左右子树的先序遍历与中序遍历序列,接着我们可以用递归的方法去构建左子树、右子树。

Java代码:

/**
 * <p>
 * 题目(剑指offer page55):
 * <p>
 * 输入某二叉树的前序遍历和中序遍历结果,请重建二叉树。
 * <p>
 * 假设前序遍历和中序遍历中不含重复数字。
 * 
 * @author likebamboo
 */
public class ConstructeBinTree {

    /**
     * 构建二叉树
     * 
     * @param preOrder 先序遍历结果
     * @param inOrder 中序遍历结果
     * @return
     */
    private TreeNode constructeTree(int[] preOrder, int[] inOrder) {
        if (preOrder == null || inOrder == null || preOrder.length != inOrder.length) {
            return null;
        }
        return constructe(preOrder, 0, preOrder.length - 1, inOrder, 0, inOrder.length - 1);
    }

    /**
     * 构建二叉树的任意子树
     * 
     * @param preOrder 先序遍历结果
     * @param startPre 先序遍历开始位置
     * @param endPre 先序遍历结束位置
     * @param inOrder 中序遍历结果
     * @param startIn 中序遍历开始位置
     * @param endIn 中序遍历结束位置
     * @return
     */
    private TreeNode constructe(int[] preOrder, int startPre, int endPre, int[] inOrder,
            int startIn, int endIn) {
        if ((endPre - startPre) != (endIn - startIn)) {
            return null;
        }
        if (preOrder == null || inOrder == null || preOrder.length == 0 || inOrder.length == 0) {
            return null;
        }
        // 前序遍历的第一个节点为根节点
        int rootValue = preOrder[startPre];
        TreeNode root = new TreeNode();
        root.setValue(rootValue);

        // 只有一个元素,返回该节点
        if (startPre == endPre && startIn == endIn) {
            return root;
        }

        int rootIdx = -1, count = 0;
        // 遍历中序遍历结果,找到根节点的值
        for (int i = startIn; i <= endIn; ++i, ++count) {
            if (rootValue == inOrder[i]) {
                rootIdx = i;
                break;
            }
        }

        // 没有在中序遍历中找到该节点。
        if (rootIdx == -1) {
            return null;
        }

        if (count > 0) {
            // 构建左子树
            root.setLeftNode(constructe(preOrder, startPre + 1, startPre + count, inOrder, startIn,
                    rootIdx - 1));
        }

        if (endPre > startPre + count) {
            // 构建右子树
            root.setRightNode(constructe(preOrder, startPre + count + 1, endPre, inOrder,
                    rootIdx + 1, endIn));
        }
        return root;
    }

    public static void main(String[] args) {
        ConstructeBinTree binTree = new ConstructeBinTree();
        int[] preOrder1 = new int[] {
                1, 2, 4, 7, 3, 5, 6, 8
        };
        int[] inOrder1 = new int[] {
                4, 7, 2, 1, 5, 3, 8, 6
        };

        int[] preOrder2 = new int[] {
                1, 2, 4, 7, 3, 5, 6, 8
        };
        int[] inOrder2 = new int[] {
                8, 6, 5, 3, 7, 4, 2, 1
        };
        TreeNode root = binTree.constructeTree(preOrder1, inOrder1);
        System.out.println("普通二叉树 ,结果:" + root);
        root = binTree.constructeTree(preOrder2, inOrder2);
        System.out.println("只有左节点的二叉树 ,结果:" + root);
    }
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值