二叉树前序后序中序互推总结

来源:互联网 发布:淘宝 全球购 费用 编辑:程序博客网 时间:2024/06/11 10:32

最近笔试题一直遇到这个题,今天就总结一下。本文主要回答以下几个问题(Java实现):

  1. 前序 + 中序 => 后序 + 层序
  2. 后序 + 中序 => 前序 + 层序
  3. 以上2个问题的2种解决办法(a. 手写出二叉树 b. 编程实现)

先看以下3种遍历的特点:

图中表示的是不同序中的根节点左子树右子树的位置

特点:

  1. 前序的第一个是root,后序的最后一个是root。
  2. 每种排序左子树右子树分布都是有规律的,见上图。
  3. 对于每一个子树(左/右)可以看成一个全新的树,仍然遵循上面的规律。

根据上面的特点,可以解决问题核心都是中序的结构特点:可以明确区分出左子树右子树的位置):
前+中=>后+层:

  1. 前序的第一个就是root,对应找到中序中根的位置,那么中序根前面的就是左子树,后面的就是右子树。
  2. 数一下左子树右子树的元素个数,对应在前序中找到左子树右子树的位置,如上图标示。
  3. 那么,下面对于左子树右子树又是一个全新的树,仍然按照以上规律,即在前序左子树L中,第一个元素B是root(同时也是父节点A的左节点),在前序右子树R中,第一个元素C是root(同时也是父节点A的右节点)……
  4. 重建出二叉树之后,后序/层序就是遍历就OK了。

后+中=>前+层:(类似上面的方法,就是后序的根节点在尾部,相应的左子树/右子树的根节点B/C在尾部,见上图所示。)

具体解决办法:

  1. 若是选择题,直接手写出二叉树,有了二叉树之后,什么序都秒秒钟的事。
  2. 若是编程题,那就要动手实现了,具体有2个思路:a. 直接递归打印各种序的排列(不用重建二叉树)。 b. 先重建出二叉树,再各种序的遍历打印。

实现:

  1. 手写:

    这里写图片描述

  2. 代码实现:

    直接递归打印,不用重建二叉树

    前序+中序=>后序


public class PreOrderAndInOrder {    /**     *     * @param pre_bg_index 前序数组中,开始的索引(具体到左(右)子树中,数组开始索引+长度len精确指定了某一个左(右)子树)     * @param in_bg_index 中序数组中,开始的索引     * @param len 树(左(右)子树对应到数组中的长度)     * @param pre_Order_Array 前序数组     * @param in_Order_Array 中序数组 (这里一直把前序中序数组当做参数,是由于在递归过程中,没有动过数组,只是动态的去其中的某些项。)     */    public static void postOrderSolution(int pre_bg_index, int in_bg_index, int len, char[] pre_Order_Array, char[] in_Order_Array) {        if (len == 0)            return;        char root = pre_Order_Array[pre_bg_index];        if (len==1){//递归出口。            System.out.print(root+" ");            return;        }        int i = 0;        while (root != in_Order_Array[in_bg_index + i]) {//找到中序根节点的位置。            i++;        }        //左右中,标准的后序遍历的形式。        postOrderSolution(pre_bg_index+1, in_bg_index, i, pre_Order_Array, in_Order_Array);        postOrderSolution(pre_bg_index+i+1, in_bg_index+i+1, len-i-1, pre_Order_Array, in_Order_Array);        System.out.print(root+" ");    }    public static void main(String[] args){        char[] pre_Order_Array = {'A','B','D','E','H','C','F','G','I'};        char[] in_Order_Array = {'D','B','H','E','A','F','C','G','I'};        postOrderSolution(0, 0, pre_Order_Array.length, pre_Order_Array, in_Order_Array);    }}

后序+中序=>前序(与上面大体类似,就是后序的下标用于定位根节点的位置与前序不同)


public class InOrderAndPostOrder {    /**     *     * @param post_end_index 后序数组中,结束的索引(具体到左(右)子树中,数组结束索引+长度len精确指定了某一个左(右)子树)     * @param in_bg_index 中序数组中,开始的索引     * @param len 树(左(右)子树对应到数组中的长度)     * @param post_Order_Array 后序数组     * @param in_Order_Array 中序数组 (这里一直把前序中序数组当做参数,是由于在递归过程中,没有动过数组,只是动态的去其中的某些项。)     */    public static void preOrderSolution(int post_end_index, int in_bg_index, int len, char[] post_Order_Array, char[] in_Order_Array) {        if (len == 0)            return;        char root = post_Order_Array[post_end_index];        if (len==1){//递归出口。            System.out.print(root+" ");            return;        }        int i = 0;        while (root != in_Order_Array[in_bg_index + i]) {//找到中序根节点的位置。            i++;        }        //中左右,标准的前序遍历的形式。注意左子树中后序结束的索引是从后往前减的,中间减掉的(len-i-1)是右子树对应的数组长度。        System.out.print(root+" ");        preOrderSolution(post_end_index-(len-i-1)-1, in_bg_index, i, post_Order_Array, in_Order_Array);        preOrderSolution(post_end_index-1, in_bg_index+i+1, len-i-1, post_Order_Array, in_Order_Array);    }    public static void main(String[] args){        char[] post_Order_Array = {'D','H','E','B','F','I','G','C','A'};        char[] in_Order_Array = {'D','B','H','E','A','F','C','G','I'};        preOrderSolution(post_Order_Array.length-1, 0, post_Order_Array.length, post_Order_Array, in_Order_Array);    }}

重建二叉树,然后各种序遍历输出,这里以 前序+中序=>后序+层序 为例:


public class TreeNode {    char val;    TreeNode left;    TreeNode right;    public TreeNode(char val) {        this.val = val;    }}

public class ReConstructPreAndIn {    /**     * @param pre_bg_index    前序数组中,开始的索引(具体到左(右)子树中,数组开始索引+长度len精确指定了某一个左(右)子树)     * @param in_bg_index     中序数组中,开始的索引     * @param len             树(左(右)子树对应到数组中的长度)     * @param pre_Order_Array 前序数组     * @param in_Order_Array  中序数组 (这里一直把前序中序数组当做参数,是由于在递归过程中,没有动过数组,只是动态的去其中的某些项。)     */    public static TreeNode reConstruct(int pre_bg_index, int in_bg_index, int len, char[] pre_Order_Array, char[] in_Order_Array) {        if (len == 0)            return null;        char root = pre_Order_Array[pre_bg_index];        if (len == 1) {//递归出口。            TreeNode newNode = new TreeNode(root);            return newNode;        }        int i = 0;        while (root != in_Order_Array[in_bg_index + i]) {//找到中序根节点的位置。            i++;        }        TreeNode node = new TreeNode(root);        node.left = reConstruct(pre_bg_index + 1, in_bg_index, i, pre_Order_Array, in_Order_Array);        node.right = reConstruct(pre_bg_index + i + 1, in_bg_index + i + 1, len - i - 1, pre_Order_Array, in_Order_Array);        return node;    }    //后序遍历    public static void postOrderTransverse(TreeNode root) {        if (root == null)            return;        if (root.left == null && root.right == null) {            System.out.print(root.val + " ");            return;        }        postOrderTransverse(root.left);        postOrderTransverse(root.right);        System.out.print(root.val + " ");    }    //层序遍历    public static void levelOrderTransverse(TreeNode root){        Queue<TreeNode> queue = new LinkedList<>();        queue.add(root);        TreeNode node;        while (!queue.isEmpty()){            node = queue.peek();            System.out.print(node.val+" ");            queue.poll();            if(node.left!=null)                queue.add(node.left);            if(node.right!=null)                queue.add(node.right);        }    }    public static void main(String[] args) {        char[] pre_Order_Array = {'A', 'B', 'D', 'E', 'H', 'C', 'F', 'G', 'I'};        char[] in_Order_Array = {'D', 'B', 'H', 'E', 'A', 'F', 'C', 'G', 'I'};        TreeNode root = reConstruct(0, 0, pre_Order_Array.length, pre_Order_Array, in_Order_Array);        postOrderTransverse(root);        System.out.println();        levelOrderTransverse(root);    }}

End