【算法】重建二叉树

首先,已知前序和中序,可以确定唯一一个二叉树;

           已知后序和中序,可以确定唯一一个二叉树;

此部分内容来自-------------- 作者:Q-WHai 来源:CSDN 原文:https://blog.csdn.net/lemon_tree12138/article/details/49798221?utm_source=copy

具体数据如下:

前序:A B D E H I C F G
中序:D B H E I A F C G

1.递归重建

  在上面的前序序列中,我们可以很容易地获得A就是根节点。此时,我们可以在后序序列中找到这个A,那么在A的左边就是A的左孩子及其子节点,在A的右边就是A的右孩子及其子节点。假设,我们目前在A的左边。在遍历前序序列到B的时候,我就知道了B就是A的左孩子,而在B的左边(中序序列)的都是B的左孩子及其子节点,在B的右边(同是也在A的左边)的就是B的右孩子及其子节点...以此类推.这就是利用递归来重建二叉树。

 

2.建立节点集

  关于这种方法,如果你对B树有所了解,也就不难理解了。因为后面我会单独写一篇关于B树的文章,这里就暂时一笔代过,说说思路就好了。

  为子节点建立节点集。在遍历(前/后序遍历的序列)的过程中,分裂和修正这个节点集。

 

3.创建索引函数

  前面的两种方法,其实可以说是同一种方法,也是比较常见的方法,《编程之美》里使用的正是常见的递归调用。下面的这种方法是本文的重点,我在其他地方并没有见到过类似的方法,于是在此记录一下思路和过程。我当时也只是灵光一闪,想到还可以用这样巧妙的方法来实现。真是让人兴奋。下面看看具体实现过程。

  让前/后序遍历的序列拥有中序遍历序列的索引,在遍历(前/后序遍历的序列)的过程中按照二叉排序树的方法直接插入即可.

图-4 节点索引函数对照表

  看到这个表,是不是有一种似曾相识的感觉。这个在KMP模式匹配也有一个类似的INDEX函数,在KMP里叫作next.这里我给他取名叫作index吧。因为这个index很直观,就是取了某一个节点的下标,并保存。

  其实在已知的遍历序列中,如果含有中序遍历结果,那么我们都可以采用上面的这种创建索引函数的方式来简化重建过程。可能你会问我为什么会这样?下面请看图-4.

图-5 二叉树的中序遍历顺序示意图

  我们可以把图-2中的中序遍历二叉树过程平摊开,就可以获得图-5中这样的一个顺序序列。

  从上面的图-5中我们可以发现一个现象,那就是某一个节点的左孩子一定是在这个节点的左边,其右孩子一定是在这个节点的右边(当然,这个现象也可以从中序遍历的定义获得)。也就是节点Node的左孩子Left的值一定是比Node的值小,而Node右孩子Right的值一定是比Node的值大。

  这样的一些描述是不是似曾相识呢?没错,在二叉排序树中正是这样定义的。

  现在,我们再来看看二叉树的前序遍历过程。因为是前序,所以我们在遍历节点Node的孩子节点之前,必定是已经遍历过Node的孩子节点。这样也可以理解成是一种临近遍历的过程。

  这样看来,前序 + 中序 = 二叉排序树。于是,我们就有了以下代码:

代码:递归重建:

import java.util.*;
/**
 * Definition for binary tree
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */

public class Solution {
    public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
       if(pre.length == 0||in.length == 0){
            return null;
        }
        TreeNode node = new TreeNode(pre[0]);
        for(int i = 0; i < in.length; i++){
            if(pre[0] == in[i]){
                node.left = reConstructBinaryTree(Arrays.copyOfRange(pre, 1, i+1), Arrays.copyOfRange(in, 0, i));
                node.right = reConstructBinaryTree(Arrays.copyOfRange(pre, i+1, pre.length), Arrays.copyOfRange(in, i+1,in.length));
            }
        }
        return node;
    }
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值