(前序遍历/中序遍历)&(中序遍历/后序遍历)构造二叉树

前序遍历/中序遍历构造二叉树

根据一棵树的前序遍历与中序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。

题目来源:https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/

基本思路:
1、我们都知道,前序遍历首先遍历出的是父节点,然后是它的左子节树,最后是右子树,因此前序遍历得到的数组中第一个数是二叉树的根节点
2、知道根节点之后,在中序遍历得到数组中查找根节点对应的下标,从而将中序数组分成两个子数组,左边是根节点的左子树,右边是根节点的右子树,并且有根节点的下标,从而可以知道左子树有多少个节点,这里通过求左子树中的节点个数,从而可以更好地在前序数组中找到对应的范围。

3、同样的道理,将对左子树、右子树进行相同的操作,在前序遍历中的数组中找到它的根节点,然后再这个中序遍历的子数组中找到对应的下标,再次划分左右子数组,直到前序遍历的数组已经遍历完,二叉树构造完成.

过程分析:
在这里插入图片描述

节点类:

public class Node {
    public int value;
    public Node left;
    public Node right;
    public Node(int value){
        this.value = value;
    }

    @Override
    public String toString() {
        return value+" ";
    }
}

测试类:

import java.util.HashMap;
import java.util.Map;

/**
 * 根据中序数组、前序数组,从而构建一个二叉树,基本思路:
 * 1、由于前序遍历:首先遍历自己,然后遍历它的左子节点,最后遍历它的右子节点,因此
 * 前序数组的第一个必然是一个根节点
 * 2、知道根节点之后,在中序遍历得到的数组中找到根节点所在的下标,从而将中序数组分成两个
 * 子数组,其中左边是根节点的左子树,右边是根节点的右子树
 * 3、对每一个子数组都进行重复上面的操作(及通过递归),从而可以构建一棵二叉树
 * 当然,在中序遍历得到的数组中找根节点的下标,可以通过for循环来查找,但是相对耗时,
 * 因此这里可以使用哈希表进行优化
 */
public class ArrayToTree2 {
    public static int[] inOrder = {4,5,8,10,12,15,18};//中序遍历得到的数组
    public static int[] preOrder = {10,5,4,8,15,12,18};//前序遍历得到的数组
    //定义一个哈希表,从而存放中序数组的值及下表,并且值作为哈希表键,下标作为哈希表的值
    public static Map<Integer,Integer> map = new HashMap<>();

    public static void main(String[] args) {
        ArrayToTree2 test = new ArrayToTree2();
        for(int i = 0; i < inOrder.length; i++){
            //将中序数组存放到哈希表中,并且数组的下标作为哈希表的值,对应的值作为哈希表的键
            map.put(inOrder[i],i);
        }
        Node root = test.buildTree(inOrder, preOrder);
        System.out.print("二叉树的后序遍历: ");
        test.display(root);
    }

    /**
     * 二叉树的后序遍历
     * @param root
     */
    public void display(Node root) {
        if(root == null){
            return;//如果当前节点是null,那么结束遍历
        }
        display(root.left);
        display(root.right);
        System.out.print(root.value+" ");
    }

    public Node buildTree(int[] inOrder, int[] preOrder) {
        return buildTree(inOrder,0,inOrder.length,preOrder,0,preOrder.length);//方法的重载
    }

    private Node buildTree(int[] inOrder, int in_start, int in_end, int[] preOrder, int pre_start, int pre_end) {
        if(pre_start >= pre_end){
            //如果前序遍历得到的数组已经遍历完了,那么就将结束递归
            return null;
        }
        int value = preOrder[pre_start];//前序遍历得到的数组第一个是根节点
        Node root = new Node(value);//构造根节点
        /*
        //在中序遍历得到的数组中找到这个节点的下标
        int i = in_start;//值得注意的是,这里不可以是从0开始遍历中序数组,因为最后将其分成左右子数组
        for(; i < in_end; i++){
            if(inOrder[i] == value){
                break;//找到了根节点所在的位置
            }
        }
        */
        int i = map.get(value);//通过哈希表,从而可以得到根节点对应的下标
        //这一步十分重要的,统计左子树有多少个节点,不可以认为i就是想要的,因为考虑到了子数组的存在
        int size = i - in_start;
        //通过递归,从而对左右子数组进行构造,分别找到左右子数组中的根节点,然后再分别对他的左右子数组进行构造
        root.left = buildTree(inOrder,in_start,i,preOrder,pre_start + 1,pre_start + 1 + size);
        root.right = buildTree(inOrder,i + 1,in_end,preOrder,pre_start + 1 + size,pre_end);
        return root;
    }
}

中序遍历/后序遍历构造二叉树

根据一棵树的中序遍历与后序遍历构造二叉树。

注意:
你可以假设树中没有重复的元素。
题目来源:https://leetcode-cn.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/
思路和上面的思路是一样的,主要是找到中序数组中的左子数组和后序数组中对应的左子数组,中序数组中的右子数组和后序数组中对应的右子数组。其基本思路为:
1、我们都知道,后序遍历是首先遍历左子树,然后遍历右子树,最后遍历父节点,因此我们可以知道在后序数组中最后一个数就是根节点
2、通过循环遍历/或者利用哈希表,从而可以在中序数组中找到对应的根节点的下标,从而可以知道将中序数组分成两个子数组,并且根节点的左边是左子数组,右边是根节点的右子数组,并且可以知道左子树的节点个数size,并且通过这个size,从而可以在后序数组中找到对应的左右子树组
3、通过递归,从而对左右子数组进行上面的步骤

由于思路适合上面的思路是一样的,这里就不再画分析图了哈。

测试类:

import java.util.HashMap;
import java.util.Map;

public class ArrayToTree3 {
    public static int[] inOrder = {4,5,8,10,12,15,18};//中序遍历得到的数组
    public static int[] postOrder = {4,8,5,12,18,15,10 };//后序遍历得到的数组
    //定义一个哈希表,从而存放中序数组的值及下表,并且值作为哈希表键,下标作为哈希表的值
    public static Map<Integer,Integer> map = new HashMap<>();

    public static void main(String[] args) {
        ArrayToTree3 test = new ArrayToTree3();
        for(int i = 0; i < inOrder.length; i++){
            //将中序数组存放到哈希表中,并且数组的下标作为哈希表的值,对应的值作为哈希表的键
            map.put(inOrder[i],i);
        }
        Node root = test.buildTree(inOrder, postOrder);
        System.out.print("二叉树的后序遍历: ");
        test.display(root);
    }

    /**
     * 二叉树的前序遍历
     * @param root
     */
    public void display(Node root) {
        if(root == null){
            return;//如果当前节点是null,那么结束遍历
        }
        System.out.print(root.value+" ");
        display(root.left);
        display(root.right);
    }

    public Node buildTree(int[] inOrder, int[] postOrder) {
        return buildTree(inOrder,0,inOrder.length,postOrder,0,postOrder.length);
    }

    private Node buildTree(int[] inOrder, int in_start, int in_end, int[] postOrder, int post_start, int post_end) {
        if(post_start >= post_end){
            //如果前序遍历得到的数组已经遍历完了,那么就将结束递归
            return null;
        }
        int value = postOrder[post_end - 1];//后序遍历得到的数组最后一个是根节点
        Node root = new Node(value);//构造根节点
        /*
        //在中序遍历得到的数组中找到这个节点的下标
        int i = in_start;//值得注意的是,这里不可以是从0开始遍历中序数组,因为最后将其分成左右子数组
        for(; i < in_end; i++){
            if(inOrder[i] == value){
                break;//找到了根节点所在的位置
            }
        }
        */
        int i = map.get(value);//通过哈希表,从而可以得到根节点对应的下标
        //这一步十分重要的,统计左子树有多少个节点,不可以认为i就是想要的,因为考虑到了子数组的存在
        int size = i - in_start;
        //通过递归,从而对左右子数组进行构造,分别找到左右子数组中的根节点,然后再分别对他的左右子数组进行构造
        root.left = buildTree(inOrder,in_start,i,postOrder,post_start,post_start + size);
        root.right = buildTree(inOrder,i + 1,in_end,postOrder,post_start + size,post_end - 1);//这里需要注意的是,右子数组在中序数组中对应后序数组中的范围是[post_start + size, post_end -1],post_end记得要减1,否则就会抛错java.lang.StackOverflowError
        return root;
    }
}

写的不好的地方,或者有错的,希望大家指正哈!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值