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

  填空题:已知一棵二叉树前序遍历和中序遍历分别为ABDEGCFH和DBGEACHF,则该二叉树的后序遍历为_____________。

  答案:DGEBHFCA。

  解题过程:

  一、基本概念扫盲:对一棵二叉树进行遍历,我们可以采取3中顺序进行遍历,分别是前序遍历、中序遍历和后序遍历。

  前序遍历:根节点 -> 左节点 -> 右节点

  中序遍历:左节点 -> 根节点 -> 右节点

  后序遍历:左节点 -> 右节点 -> 根节点

  我们可以发现,根节点是带头大哥,前序就是大哥打头阵,中序就是大哥居中指挥,后序就是大哥坐镇后方。

  二、分析前序和中序的特点:

  1、前序的第一个节点,必然是大哥;

  2、大哥在中序必然居中,自然可以把中序拆分为左右两颗子树;

  3、对左右子树重复上面过程,最终必然能把整颗二叉树还原出来。

  三、对二叉树进行后序遍历。

  四、理论讲完了,回归题目:

  前序遍历:ABDEGCFH

  中序遍历:DBGEACHF

  1、从前序找到大哥:A,那么左子树为:DBGE,右子树:CHF

      A

     /       \

          DBGE     CHF

 

  2、对左子树递归,从前序找到大哥:B,那么左子树的左子树是:D,左子树的右子树是:GE

                                                    A

                                                 /      \

                                              B       CHF

                                           /     \

                                        D      GE

 

  3、对左子树的左子树没必要递归了,就一个节点D,对左子树的右子树递归,从前序找到大哥:E,那么左子树的右子树的左子树是:G

                                                                                                   

                                                    A

                                                 /      \

                                              B       CHF

                                           /     \

                                        D        E

                                                 /

                                              G

 

  4、左子树已经递归完,右子树依葫芦画瓢,最终还原出来的二叉树就是它:

                            

                                                    A

                                                 /      \

                                              B         C

                                           /     \           \

                                        D        E         F

                                                 /              \

                                              G                H

 

  5、对它做后序遍历:DGEBHFCA

  好了,以上就是解题全过程。作为程序员,应该充分利用手头的工具来解题——计算机。所以我们需要进一步对该题建模,思考模型的算法。巧了,letCode的第105题就是这个题目,大家可以移步去力扣看题解。这里给出最简单的递归算法实现:

/**
 * 二叉树构造,根据前序遍历、中序遍历,获取二叉树
 * @author wulf 
 */
public class BTree {

    /**
     * 构造二叉树
     *
     * @param preOrder 前序遍历数组
     * @param inOrder  中序遍历数组
     * @return
     */
    public TreeNode buildTree(String[] preOrder, String[] inOrder) {
        return buildTreeByRecursion(preOrder, 0, preOrder.length, inOrder, 0, inOrder.length);
    }

    /**
     * 递归构造二叉树
     *
     * @param preOrder      前序遍历数组
     * @param preOrderStart
     * @param preOrderEnd
     * @param inOrder       中序遍历数组
     * @param inOrderStart
     * @param inOrderEnd
     */
    private TreeNode buildTreeByRecursion(String[] preOrder, int preOrderStart, int preOrderEnd,
                                          String[] inOrder, int inOrderStart, int inOrderEnd) {
        if (preOrderStart == preOrderEnd) {
            return null;
        }

        // 根节点值
        String rootValue = preOrder[preOrderStart];

        // 构造根节点
        TreeNode rootNode = new TreeNode(rootValue);

        // 在中序遍历中找到根节点位置
        int rootIndex = 0;
        for (int i = inOrderStart; i < inOrderEnd; i++) {
            if (inOrder[i].equals(rootValue)) {
                rootIndex = i;
                break;
            }
        }

        int leftNum = rootIndex - inOrderStart;

        // 递归的构造左子树
        rootNode.left = buildTreeByRecursion(preOrder, preOrderStart + 1, preOrderStart + leftNum + 1,
                inOrder, inOrderStart, rootIndex);
        // 递归的构造右子树
        rootNode.right = buildTreeByRecursion(preOrder, preOrderStart + leftNum + 1, preOrderEnd,
                inOrder, rootIndex + 1, inOrderEnd);

        return rootNode;
    }

    /**
     * 后续遍历
     *
     * @param treeNode 二叉树对象
     */
    private void postOrder(TreeNode treeNode) {
        if (treeNode != null) {
            postOrder(treeNode.left);
            postOrder(treeNode.right);
            System.out.print(treeNode.val + " ");
        }
    }


    /**
     * 测试
     *
     * @param args
     */
    public static void main(String[] args) {
        String[] preOrder = {"A", "B", "D", "E", "G", "C", "F", "H"};
        String[] inOrder = {"D", "B", "G", "E", "A", "C", "H", "F"};
        BTree bTree = new BTree();
        TreeNode treeNode = bTree.buildTree(preOrder, inOrder);
        System.out.println("二叉树:" + treeNode);
        System.out.println("后续遍历:");
        bTree.postOrder(treeNode);
    }

    /**
     * 二叉树对象
     */
    private class TreeNode {
        String val; //节点数据
        TreeNode left;  //左节点
        TreeNode right; //右节点

        TreeNode() {
        }

        TreeNode(String val) {
            this.val = val;
        }

        TreeNode(String val, TreeNode left, TreeNode right) {
            this.val = val;
            this.left = left;
            this.right = right;
        }

        public String toString() {
            StringBuilder sb = new StringBuilder();
            sb.append(val);
            sb.append(",");
            sb.append(left);
            sb.append(",");
            sb.append(right);
            return sb.toString();
        }
    }
}

 

  运行结果:

二叉树:A,B,D,null,null,E,G,null,null,null,C,null,F,H,null,null,null
后续遍历:
D G E B H F C A 

 

          

posted on 2019-12-26 15:18  不想下火车的人  阅读(3064)  评论(0)    收藏  举报

导航