练习题--根据前序遍历和中序遍历计算后序遍历

通过前序遍历确定根节点,利用中序遍历划分左、右子树,递归构建二叉树,最终实现后序遍历。实例演示了解决此类问题的方法。

当给定前序遍历和中序遍历结果时,我们可以通过递归的方式来构建二叉树,并获取其后序遍历结果。下面我们再举一个例子来演算。

给定前序遍历结果 preorder = [1,2,4,5,3,6,7] 和中序遍历结果 inorder = [4,2,5,1,6,3,7]

首先,我们可以确定前序遍历的第一个元素 1 是根节点的值。然后我们在中序遍历结果中找到根节点的位置,即 inorder.index(1) = 3,说明根节点在中序遍历结果中的位置是在索引为3的位置。

接下来,我们可以根据中序遍历结果的划分,将左子树和右子树的元素分开:

左子树的中序遍历结果为 [4,2,5],对应的前序遍历结果为 [2,4,5]
右子树的中序遍历结果为 [6,3,7],对应的前序遍历结果为 [3,6,7]

然后,我们可以递归地构建左子树和右子树:

对于左子树,根据前序遍历结果 [2,4,5] 和中序遍历结果 [4,2,5],可以得到左子树的根节点为 2,继续递归构建左子树和右子树;
对于右子树,根据前序遍历结果 [3,6,7] 和中序遍历结果 [6,3,7],可以得到右子树的根节点为 3,继续递归构建左子树和右子树。

最终,我们可以得到构建的二叉树如下所示:

     1
    / \
   2   3
  / \   \
 4   5   6
         \
          7

最后,我们可以对构建的二叉树进行后序遍历,得到后序遍历结果为 [4, 5, 2, 7, 6, 3, 1]

总结一下解决这类题的思路:

  1. 首先,根据前序遍历结果确定根节点的值,并在中序遍历结果中找到根节点的位置,将中序遍历结果划分为左子树和右子树。
  2. 然后,递归地构建左子树和右子树,直到叶子节点。
  3. 最后,根据构建的二叉树进行后序遍历,得到后序遍历结果。

通过以上演算,我们成功地根据给定的前序遍历和中序遍历结果构建了二叉树,并获取了其后序遍历结果。希望这个例子和总结能帮助你更好地理解解决这类题的思路。

<think>我们已知二叉树的先序遍历(Pre-order)序遍历(In-order),可以唯一确定一棵二叉树,进而后序遍历(Post-order)。解的基本思路是递归重建二叉树,然后在重建过程中(或重建后)进行后序遍历。 ### 解步骤: 1. **先序遍历**的第一个节点是根节点。 2. 在**中序遍历**中找到这个根节点,则根节点左侧是左子树的中序遍历,右侧是右子树的中序遍历。 3. 根据左子树的节点数量,可以在先序遍历中确定左子树右子树的先序遍历序列。 4. 递归处理左子树右子树。 5. 后序遍历的顺序是:左子树 -> 右子树 -> 根节点。在递归过程中,我们可以在递归完左右子树后输出根节点(或存储),这样就得到了后序遍历。 ### 示例题目: 假设已知序遍历序列为:`[1, 2, 4, 5, 3, 6, 7]`,中序遍历序列为:`[4, 2, 5, 1, 6, 3, 7]`,后序遍历序列。 #### 步骤解析: 1. 先序遍历第一个节点是1,所以根节点是1。 2. 在中序遍历中找到1,则中序遍历被分为: - 左子树中序:`[4, 2, 5]` - 右子树中序:`[6, 3, 7]` 3. 根据左子树节点数量(3个),将先序遍历中根节点后面的3个节点作为左子树的先序:`[2,4,5]`,剩下的为右子树的先序:`[3,6,7]`。 4. 递归处理左子树: - 左子树的先序:`[2,4,5]`,中序:`[4,2,5]` - 根节点是2,中序中2的左边是`[4]`(左子树),右边是`[5]`(右子树)。 - 递归处理左子树:先序`[4]`,中序`[4]` -> 节点4。 - 递归处理右子树:先序`[5]`,中序`[5]` -> 节点5。 5. 递归处理右子树: - 右子树的先序:`[3,6,7]`,中序:`[6,3,7]` - 根节点是3,中序中3的左边是`[6]`(左子树),右边是`[7]`(右子树)。 - 递归处理左子树:先序`[6]`,中序`[6]` -> 节点6。 - 递归处理右子树:先序`[7]`,中序`[7]` -> 节点7。 6. 后序遍历:先遍历左子树(4,5,2),然后右子树(6,7,3),最后根节点1。所以后序遍历序列为:`[4,5,2,6,7,3,1]`。 ### 代码实现(Python): 我们可以通过递归重建二叉树,然后进行后序遍历。也可以直接递归输出后序遍历序列(不显式构建树)。 #### 方法一:递归构建二叉树,然后后序遍历 ```python class TreeNode: def __init__(self, val=0, left=None, right=None): self.val = val self.left = left self.right = right def build_tree(preorder, inorder): if not preorder or not inorder: return None root_val = preorder[0] root = TreeNode(root_val) index = inorder.index(root_val) root.left = build_tree(preorder[1:1+index], inorder[:index]) root.right = build_tree(preorder[1+index:], inorder[index+1:]) return root def postorder_traversal(root): if not root: return [] return postorder_traversal(root.left) + postorder_traversal(root.right) + [root.val] # 测试 preorder = [1, 2, 4, 5, 3, 6, 7] inorder = [4, 2, 5, 1, 6, 3, 7] root = build_tree(preorder, inorder) print(postorder_traversal(root)) # 输出: [4,5,2,6,7,3,1] ``` #### 方法二:直接递归生成后序遍历序列(不构建树) ```python def get_postorder(preorder, inorder): if not preorder: return [] root_val = preorder[0] index = inorder.index(root_val) left_post = get_postorder(preorder[1:1+index], inorder[:index]) right_post = get_postorder(preorder[1+index:], inorder[index+1:]) return left_post + right_post + [root_val] # 测试 preorder = [1, 2, 4, 5, 3, 6, 7] inorder = [4, 2, 5, 1, 6, 3, 7] print(get_postorder(preorder, inorder)) # 输出: [4,5,2,6,7,3,1] ``` ### 练习题: 1. 已知序遍历序列:`[3,9,20,15,7]`,中序遍历序列:`[9,3,15,20,7]`,后序遍历序列。 2. 已知序遍历序列:`[1,2,3,4,5]`,中序遍历序列:`[5,4,3,2,1]`,后序遍历序列。 3. 已知序遍历序列:`[1,2,4,8,9,5,10,3,6,7]`,中序遍历序列:`[8,4,9,2,10,5,1,6,3,7]`,后序遍历序列。 ### 练习答案: 1. 后序遍历:`[9,15,7,20,3]` 2. 后序遍历:`[5,4,3,2,1]` (注意:这是一个右斜树) 3. 后序遍历:`[8,9,4,10,5,2,6,7,3,1]` ### 总结: 通过先序中序后序,关键在于递归地确定根节点左右子树的范围。递归过程中,先序序列的第一个节点总是当前子树的根节点,然后在中序序列中找到该根节点,划分左右子树。最后,按照后序遍历的顺序(左子树、右子树、根节点)输出结果即可[^1][^2][^3]。 §§相关问题§§ 1. 已知后序序遍历结果,如何序遍历结果? 2. 为什么已知先序后序遍历结果不能唯一确定一棵二叉树? 3. 二叉树遍历算法竞赛中的常见应用有哪些?</think>### 已知先序序遍历后序遍历练习题 根据引用[1][2][3]的原理,已知先序序遍历可唯一确定二叉树结构,进而推导出后序遍历。以下是精选的练习题(含解析步骤): --- #### **练习题 1** 已知-序遍历:`[A, B, D, E, C, F, G]` -序遍历:`[D, B, E, A, F, C, G]` 后序遍历结果。 **解析步骤**: 1. 先序首元素 `A` 是根节点(引用[2])。 2. 在中序中找到 `A`,划分左右子树: - 左子树中序:`[D, B, E]` - 右子树中序:`[F, C, G]` 3. 根据左子树节点数(3个),划分先序: - 左子树先序:`[B, D, E]` - 右子树先序:`[C, F, G]` 4. 递归处理左子树: - 左子树的根 `B`(先序首元素) - 中序划分:`[D]`(左)、`[E]`(右) → 后序:`[D, E, B]` 5. 递归处理右子树: - 根 `C`,中序划分:`[F]`(左)、`[G]`(右) → 后序:`[F, G, C]` 6. 合并结果:`[D, E, B, F, G, C, A]` **答案**:`D, E, B, F, G, C, A` [^1][^2] --- #### **练习题 2** 已知-序遍历:`[G, D, A, F, E, M, H, Z]` -序遍历:`[A, D, E, F, G, H, M, Z]` 后序遍历结果。 **解析步骤**: 1. 根节点 `G`(先序首元素)。 2. 中序划分: - 左子树中序:`[A, D, E, F]` - 右子树中序:`[H, M, Z]` 3. 划分先序: - 左子树先序:`[D, A, F, E]`(节点数4) - 右子树先序:`[M, H, Z]` 4. 左子树递归- 根 `D` → 中序划分:`[A]`(左)、`[E, F]`(右) - 右子树 `[E, F]`:根 `F` → 后序:`[E, F]` - 左子树后序:`[A, E, F, D]` 5. 右子树递归- 根 `M` → 中序划分:`[H]`(左)、`[Z]`(右) - 后序:`[H, Z, M]` 6. 合并结果:`[A, E, F, D, H, Z, M, G]` **答案**:`A, E, F, D, H, Z, M, G` [^2][^3] --- #### **练习题 3** 已知-序遍历:`[1, 2, 4, 5, 3, 6, 7]` -序遍历:`[4, 2, 5, 1, 6, 3, 7]` 后序遍历结果。 **解析步骤**: 1. 根节点 `1`。 2. 中序划分: - 左子树:`[4, 2, 5]` - 右子树:`[6, 3, 7]` 3. 划分先序: - 左子树先序:`[2, 4, 5]` - 右子树先序:`[3, 6, 7]` 4. 左子树递归- 根 `2` → 中序划分:`[4]`(左)、`[5]`(右) → 后序:`[4, 5, 2]` 5. 右子树递归- 根 `3` → 中序划分:`[6]`(左)、`[7]`(右) → 后序:`[6, 7, 3]` 6. 合并结果:`[4, 5, 2, 6, 7, 3, 1]` **答案**:`4, 5, 2, 6, 7, 3, 1` [^1][^3] --- ### 关键算法总结 1. **根节点定位**:先序序列的第一个元素是根节点(引用[2])。 2. **子树划分**:用根节点在中序序列中的位置划分左右子树(引用[3])。 3. **递归处理**:对左右子树重复上述过程,直到子树为空。 4. **后序生成**:按 **左子树 → 右子树 → 根** 的顺序合并结果(引用[1])。 > 时间复杂度:$O(n)$(每个节点处理一次)[^1][^3]。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值