<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]。
---