已知前序遍历和中序遍历,求后序遍历

有这么一道面试题:已知一棵二叉树的前序遍历结果为ABCDEFGHI,中序遍历结果为CBDEAFHGI,则后序遍历的结果为( )。

这个题目很简单,很多应聘者都知道结果,而且也能够分析他的思路,但要求写代码却有不少人写不出来。

思路大家都知道:前序遍历列表的第一个点,是树的根节点;它在中序遍历列表的位置,把中序遍历列表分为左右两截,左边为左子树,右边为右子树。然后,再分别对左右子树进行同样的操作,这样就可以把整棵树给构造出来,然后对树进行后序遍历。

这里写图片描述

最简单的方法,当然就是用递归了,代码如下:

import java.util.List;
import java.util.function.Consumer;

import javax.annotation.Nullable;

import com.google.common.collect.Lists;

/**
 * 已知前序遍历和中序遍历,求后序遍历
 * 
 * @author liuwenzhe2008@qq.com
 *
 */
public class Tree<T> {

  private final T value;
  @Nullable private Tree<T> left;
  @Nullable private Tree<T> right;

  public Tree(T value) {
    this.value = value;
  }

  /**
   * 解析前序遍历和中序遍历,创建树并返回根节点
   * <p>
   * @param preorder 前序遍历输入
   * @param inorder 中序遍历输入
   * @return 创建出来的树
   */
  @Nullable
  public static <T> Tree<T> from(List<T> preorder, List<T> inorder) {
    // 参数检测:必须一样长
    if (preorder.size() != inorder.size()) {
      throw new IllegalArgumentException("Preorder and Inorder should have the same size.");
    }

    // 没有元素的情况
    if (preorder.isEmpty()) {
      return null;
    }

    // 找出前序遍历列表里第一个元素在中序遍历列表的位置,
    T first = preorder.get(0);
    int index = inorder.indexOf(first);

    // 把中序遍历列表分成左右两截,
    List<T> mdLeft = inorder.subList(0, index);
    List<T> mdRight = inorder.subList(index + 1, inorder.size());

    // 分别跟前序遍历列表对应,确保长度相同
    List<T> fwLeft = preorder.subList(1, 1 + mdLeft.size());
    List<T> fwRight = preorder.subList(preorder.size() - mdRight.size(), preorder.size());

    // 以前序遍历的第一个元素作为根节点构造一棵树
    Tree<T> root = new Tree<>(first);

    // 递归构造左子树和右子树
    root.left = from(fwLeft, mdLeft);
    root.right = from(fwRight, mdRight);

    return root;
  }

  @Nullable
  public static Tree<Character> from(String preorder, String middle) {
    return from(Lists.charactersOf(preorder), Lists.charactersOf(middle));
  }

  /**
   * 后序遍历,提供回调onVisit
   */
  public void postorder(Consumer<T> onVisit) {
    // 遍历左子树
    if (left != null) {
      left.postorder(onVisit);
    }

    // 遍历右子树
    if (right != null) {
      right.postorder(onVisit);
    }

    // 访问根节点
    onVisit.accept(value);
  }

  /**
   * 测试:输入前序遍历列表和中序遍历列表,打印后序遍历列表
   */
  public static void main(String[] args) {
    Tree.from("ABCDEFGHI", "CBDEAFHGI").postorder(System.out::print);  // print "CEDBHIGFA";
  }
}

——- 本博客所有内容均为原创,转载请注明作者和出处 ——-

作者:刘文哲

联系方式:liuwenzhe2008@qq.com

博客:http://blog.csdn.net/liuwenzhe2008

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值