Rhyme/剑指Offer04 由先序遍历和中序遍历构造二叉树Java版

通过先序遍历和中序遍历构建二叉树的Java实现。解析遍历序列,递归构建树结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

剑指Offer04 由先序遍历和中序遍历构造二叉树Java版

package offer4;


/**
 * 剑指Offer第四题
 * <p>
 * 给出先序遍历和中序遍历,
 * 构建出这个二叉树
 * <p>
 * 假设输入的先序遍历和中序遍历中都没有重复的数字
 * 例如
 * 先序遍历{1,2,4,7,3,5,6,8}
 * 中序遍历{4,7,2,1,5,3,8,6}
 * <p>
 * <p>
 * 思路分析:
 * <p>
 * 以以上例子为例
 * <p>
 * 先序遍历的数组的第一个元素1为二叉树的根节点,
 * 中序遍历的根节点1在数组的中间为止,
 * 在中序遍历中在根节点左边的元素为左子树,右边为右子树
 * <p>
 * 因此我们可以将以上数组划分为如下:
 * <p>
 * 根节点 {1}
 * <p>
 * 左子树 先序{2,4,7} 中序{4,7,2}
 * 右子树 先序{3,5,6,8} 中序{5,3,8,6}
 * <p>
 * 好,这是第一遍分组
 * <p>
 * 之后再按照以上的方法找出左子树的根节点,右节点,再进行分组
 * 这样一直重复下去
 * 例如:
 * 左子树 先序{2,4,7} 中序{4,7,2}
 * 我们由先序遍历可以确定左子树的根节点,
 * 由中序遍历可以将数组再二分得
 * <p>
 * 左子树根节点{2}
 * <p>
 * 左子树的左子树 先序{4,7} 中序{4,7}
 * 左子树的右子树为空
 * <p>
 * <p>
 * 这有点类似分治策略的思想
 *
 * @author RhymeChiang
 * @date 2018/01/19
 **/
public class Offer4 {
    /**
     * 二叉树节点类
     */
    private static class TreeNode {
        int element;
        TreeNode left;
        TreeNode right;

        public TreeNode(int element) {
            this.element = element;
        }

        public TreeNode(int element, TreeNode left, TreeNode right) {
            this.element = element;
            this.left = left;
            this.right = right;
        }

        @Override
        public String toString() {
            return "TreeNode{" +
                    "element=" + element +
                    ", left=" + left +
                    ", right=" + right +
                    '}';
        }
    }

    /**
     * 由先序遍历和中序遍历构建二叉树
     *
     * @param firstTraverse  先序遍历数组
     * @param middleTraverse 中序遍历数组
     * @return
     */
    public static TreeNode buildTree(int[] firstTraverse, int[] middleTraverse) {

        TreeNode treeNode = null;
        if (firstTraverse.length < 1) {
            return null;
        } else if (firstTraverse.length == 1) {
            return new TreeNode(firstTraverse[0]);
        }
        // 查找root根节点在中序遍历数组中所占的位置
        int root = firstTraverse[0];
        int rootMiddleIndex = -1;
        for (int i = 0; i < middleTraverse.length; i++) {
            if (middleTraverse[i] == root) {
                rootMiddleIndex = i;
                break;
            }
        }

        /**
         * 根节点构造
         */
        treeNode = new TreeNode(root);

        /**
         * 左子树构建
         */
        int[] leftFirst = arrayCopy(firstTraverse, 1, rootMiddleIndex + 1);
        int[] leftMiddle = arrayCopy(middleTraverse, 0, rootMiddleIndex);
        treeNode.left = buildTree(leftFirst, leftMiddle);
        /**
         * 构建右子树
         */
        int[] rightFirst = arrayCopy(firstTraverse, rootMiddleIndex + 1, firstTraverse.length);
        int[] rightMiddle = arrayCopy(middleTraverse, rootMiddleIndex + 1, middleTraverse.length);
        treeNode.right = buildTree(rightFirst, rightMiddle);
        return treeNode;
    }

    private static int[] arrayCopy(int[] array, int start, int end) {
        int[] newArray = new int[end - start];
        int count = 0;
        for (int i = start; i < end; i++) {
            newArray[count] = array[i];
            count++;
        }
        return newArray;
    }

    public static void main(String[] args) {
        int[] firstTra = {1, 2, 4, 7, 3, 5, 6, 8};
        int[] middleTra = {4, 7, 2, 1, 5, 3, 6, 8};
        TreeNode treeNode = buildTree(firstTra, middleTra);
        System.out.println(treeNode);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值