算法通关村第六关——如何根据先序中序 或 中序后序恢复一颗二叉树

123 阅读3分钟

青铜挑战

如何根据二叉树的前序和中序遍历求得该树的后序遍历?

已知该二叉树的先序遍历,中序遍历序列为:D-B-G-E-A-C-F ,求该二叉树的后序遍历的序列

该怎么求?

先序遍历:头---左---右;先遍历头节点,再遍历左子树,最后遍历右子树;

中序遍历:左---头---右;中序遍历先遍历左子树,再遍历头节点,最后遍历右子树;

根据上述特点:

1.先从给定的先序遍历中确定头节点 A;

2.再从中序遍历中确定A的左右子树;左子树结构 (D-B-G-E) ,右子树结构 (C-F);

3.然后再去先序遍历中找到左子树中的头节点B,再去找B的左右子树,直到树中整体结构被确定;

画图来说明:

image.png

image.png

image.png

确定右子树也是同样的过程,就不一 一赘述了;无非就是先序遍历确定右子树根节点,再去中序遍历中找到当前根节点的左右子树;

理清了根据根据先序遍历,中序遍历,确定后序遍历的理论,那么使用代码该怎么实现呢?

只要我们通过先序和中序将整棵树的结构构造出来,那么树的后序遍历还不是手到擒来;

构造二叉树的代码如下:

    Map<Integer,Integer> dic=new HashMap<>(); // 定义一个成员变量map,用来记录中序遍历中根节点的下标;
   // 参数中给定的是先序的序列,中序的序列;
  public TreeNode buildTree(int[] preorder, int[] inorder) {
      // 通过中序遍历的序列,填充map, map中记录(节点值,节点下标)
      for(int i=0;i<inorder.length;i++){
            dic.put(inorder[i],i);
        }
        return recur(preorder,0,0,inorder.length-1);
    }
    // 利用递归构建整棵树
    TreeNode recur(int[] preorder,int root,int left,int right){
        // basecase  left>right时,说明了当前来到的节点没有子节点,直接返回空节点
        if(left>right){
            return null;
        }
        // 先构建根节点
        TreeNode node=new TreeNode(preorder[root]);
        // 根据当前根节点所在先序中的下标,找到中序遍历中根节点对应位置
        int i=dic.get(preorder[root]);
        // 构建左子树
        node.left=recur(preorder,root+1,left,i-1);
        // 构建右子树
        node.right=recur(preorder,root+i+1-left,i+1,right);
        // 返回树的结构
        return node;
    }

具体题解请看:剑指 Offer 07. 重建二叉树 - 力扣(LeetCode)

还得是大佬才能讲的明白透彻;

如何根据二叉树的中序和后序遍历求得该树的前序遍历?

明白了根据先序遍历和中序遍历,确定树的后序遍历的过程;无非也就是一个套路;

中序遍历特点:左子树---头---右子树

后序遍历特点:左子树---右子树---头

给定中序遍历 D-B-G-E-A-C-F,后序遍历D-G-E-B-F-C-A

1.首先先找头节点,不过这次头节点是在后序遍历中确定;找到后序遍历中最后一个节点A,A是整棵树的根节点;

2.然后从中序遍历中找到当前头节点A的左右子树;左子树:(D,B,G,E) 右子树 (C,F);

3.去找左子树中的节点在后序遍历的最后一个位置的节点 (D-G-E-B),会定位到B; 然后在中序遍历中去找以B为根节点的左右子树节点;

以此类推即可;

画图来说明:

image.png

image.png

image.png

只要整棵树的结构确定,那么先序遍历还不是手到擒来!!!

为什么根据先序遍历和后序遍历无法确定该树的中序遍历呢?

先序和后序遍历只会直到哪个节点是整棵树的根节点,而不会让我们已知左子树,右子树的情况;所以我们无法确定一棵树的左右子树,肯定也不能确定中序遍历顺序了。