剑指offer java学习记录-7重建二叉树

Num7-重建二叉树



一、题目描述

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建出如下图所示的二叉树并输出它的头结点。
在这里插入图片描述


二、分析题目

1. 前序遍历的顺序 根左右
2. 中序遍历的顺序 左根右
3. 目标:还原一棵二叉树
4. 特殊值部分:输入为空的情况


三、方法

1.递归

由前序遍历的特点可知,对于前序遍历而言,第一个节点必定是根节点,类似的也可以得出后序遍历的最后一个节点是根节点

对于中序遍历比较特殊,因为中序遍历的顺序是: 左根右(先遍历左子树,再遍历根节点,最后遍历右子树),所以中序遍历无法单独判断序列中的第一个节点是根节点与否

所以需要借助先序遍历先确定根节点,然后在中序遍历序列中找到该节点,那么在该节点左边的就是属于左子树的节点,右侧的就是属于右子树的节点
借助书中的图片
在这里插入图片描述

伪代码:

//有先序序列 pre[]数组, 中序遍历序列 in[]数组
1. 在 pre[]中确定第一个元素 pre[0]
2. 在 in[] 中找到 pre[0] 的位置 i, 若没找到则抛出错误,若找到则创建 pre[0] 节点
3. 接下来在 in[]0 ~ i-1 位置处找到 pre[1]
4. 在 in[] 的 i+1 ~ length-1 处寻找 pre[i+1]

代码如下:

//重建二叉树,先序遍历即中序
    public static BiTreeNode CreateTree(int[] PreOrder, int[] InOrder){
        if(PreOrder==null || InOrder==null || PreOrder.length!=InOrder.length)
            return null;
        return CreateTree(PreOrder,0, PreOrder.length-1, InOrder, 0, InOrder.length-1);
    }

    public static BiTreeNode CreateTree(int[] PreOrder,int ps, int pe, int[] InOrder, int is, int ie){
        if(is>ie)
            return null;
        //创建新节点
        BiTreeNode root = new BiTreeNode();
        int i = 0;
        while(PreOrder[ps]!=InOrder[i]&&i<=ie){
            i++;
        }
        if(i > ie)
            throw new RuntimeException("Invalid input");

        // 为节点赋值,并且递归创建左、右子树
        root.data = PreOrder[ps];
        root.lChild = CreateTree(PreOrder, ps + 1, ps + i -is, InOrder, is, i-1);
        root.rChild = CreateTree(PreOrder, ps + i - is + 1, pe, InOrder, i+1, ie);

        return root;
    }

创建二叉树类
package Base.Bitree;

import java.util.Stack;

public class BiTreeNode {
    public int data;
    public  BiTreeNode lChild;
    public BiTreeNode rChild;
    public BiTreeNode father;

    public BiTreeNode(int data){
        this.data = data;
    }
    public BiTreeNode(){}
	//先序遍历
    public void PreOrder(BiTreeNode root){
        if (root == null)
            return;
        System.out.println(root.data);
        PreOrder(root.lChild);
        PreOrder(root.rChild);
    }
	//先序非递归
    public void PreOrder2(BiTreeNode root){
        if(root==null)
            return;
        Stack<BiTreeNode> stack = new Stack<BiTreeNode>();
        BiTreeNode p = root;
        stack.push(p);
        while(p!=null&&!stack.isEmpty()){
            p = stack.pop();
            System.out.println(p.data);
            if (p.rChild!=null)
                stack.push(p.rChild);
            if(p.lChild!=null)
                stack.push(p.lChild);
        }
    }
}

主函数
主函数中调用了先序遍历作为验证

 public static void main(String[] args) {
        int[] pre = {1, 2, 4, 7, 3, 5, 6, 8};
        int[] in = {4, 7, 2, 1, 5, 3, 8, 6};
        int length = pre.length;
        BiTreeNode root;
        root = CreateTree(pre, in);
        root.PreOrder2(root);
    }

总结

在该算法的过程中得注意,pre[ ] 与 in[ ] 的索引问题,在中序中找到根节点后,左、右子树的大小也就确定了,因此索引也得在正确范围内。
在二叉树问题中一般的方法是递归解决。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值