填空题:已知一棵二叉树前序遍历和中序遍历分别为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