二叉树高频考点:后序+中序推导前序与层序遍历

二叉树高频考点:由后序+中序遍历推导前序与层序遍历(附完整Python代码)

> 摘要:二叉树遍历是算法面试的必考题型。本文从原理到代码,完整拆解"后序+中序→前序/层序"的推导过程,包含详细图解、可运行代码及4大避坑指南,建议收藏备用。


一、四种遍历方式速览

二叉树遍历的本质是根节点、左子树、右子树访问顺序的不同:

遍历方式 访问顺序 类型 作用
前序遍历 根 → 左 → 右 DFS 目标输出
中序遍历 左 → 根 → 右 DFS 🔑 分割左右子树
后序遍历 左 → 右 → 根 DFS 🔑 确定根节点
层序遍历 从上到下、从左到右 BFS 目标输出

> 核心结论 :只要知道后序 + 中序,就能唯一确定一棵二叉树,进而推导任意遍历结果。


二、重建二叉树的核心逻辑

2.1 算法步骤(三步走)

① 找根节点:后序遍历的最后一个元素 = 当前子树的根

② 分割子树:在中序遍历中找到根的位置,左侧=左子树,右侧=右子树

③ 递归重建:对左右子树重复步骤①②

2.2 关键细节:必须先右后左!

⚠️ 避坑重点 :递归重建时,必须先重建右子树,再重建左子树

原因 :我们使用 post.pop() 从后序数组末尾取元素,先取出的是右子树的根节点。若先建左子树,会导致节点匹配错误,重建失败。


三、完整Python实现

python 复制代码
from collections import deque

class TreeNode:
    """二叉树节点定义"""
    def __init__(self, val=0):
        self.val = val
        self.left = None
        self.right = None


def build_tree(inorder, postorder):
    """
    根据中序和后序遍历重建二叉树
    :param inorder: 中序遍历列表 [左→根→右]
    :param postorder: 后序遍历列表 [左→右→根]
    :return: 二叉树根节点
    """
    if not inorder:
        return None
    
    # 步骤1:后序末尾元素 = 当前根节点
    root_val = postorder.pop()
    root = TreeNode(root_val)
    
    # 步骤2:在中序中定位根节点,分割左右子树
    mid_idx = inorder.index(root_val)
    
    # 步骤3:⚠️ 必须先建右子树,再建左子树(适配pop()顺序)
    root.right = build_tree(inorder[mid_idx + 1:], postorder)
    root.left = build_tree(inorder[:mid_idx], postorder)
    
    return root


def preorder_traversal(root):
    """前序遍历:根 → 左 → 右(递归版)"""
    if not root:
        return []
    return [root.val] + preorder_traversal(root.left) + preorder_traversal(root.right)


def level_order_traversal(root):
    """层序遍历:BFS队列实现,按层分组返回"""
    if not root:
        return []
    
    q = deque([root])
    res = []
    
    while q:
        level_size = len(q)      # 🔑 记录当前层节点数
        current_level = []
        
        for _ in range(level_size):
            node = q.popleft()
            current_level.append(node.val)
            
            if node.left:
                q.append(node.left)
            if node.right:
                q.append(node.right)
        
        res.append(current_level)
    
    return res


# ==================== 测试用例 ====================
if __name__ == "__main__":
    inorder = [9, 3, 15, 20, 7]
    postorder = [9, 15, 7, 20, 3]
    
    # 1. 重建二叉树
    root = build_tree(inorder, postorder)
    
    # 2. 推导前序遍历
    preorder = preorder_traversal(root)
    
    # 3. 推导层序遍历(两种格式)
    level_order = level_order_traversal(root)
    level_flat = [val for level in level_order for val in level]
    
    print(f"中序遍历:{inorder}")
    print(f"后序遍历:{postorder}")
    print(f"前序遍历:{preorder}")
    print(f"层序遍历(按层):{level_order}")
    print(f"层序遍历(扁平):{level_flat}")

四、运行结果与图解

4.1 输出结果

中序遍历:[9, 3, 15, 20, 7]

后序遍历:[9, 15, 7, 20, 3]

前序遍历:[3, 9, 20, 15, 7]

层序遍历(按层):[[3], [9, 20], [15, 7]]

层序遍历(扁平):[3, 9, 20, 15, 7]

4.2 重建过程图解

以测试用例为例,重建步骤如下:

后序:[9, 15, 7, 20, 3] → 根=3

中序:[9, 3, 15, 20, 7] → 左=[9], 右=[15,20,7]

复制代码
    3
   / \
  9  [15,20,7]

后序弹出20 → 右子树根=20

中序[15,20,7] → 左=[15], 右=[7]

复制代码
    3
   / \
  9   20
     /  \
   15    7

4.3 遍历路径可视化

前序遍历路径(根→左→右):3 → 9 → 20 → 15 → 7

层序遍历路径(逐层访问):

第1层:[3]

第2层:[9, 20]

第3层:[15, 7]

五、四大避坑指南

坑点 错误做法 正确做法
1. 递归顺序 先左后右 ⚠️ 必须先右后左(适配pop())
2. 重复节点 直接用index() 用字典预存中序索引,避免值重复干扰
3. 层序层级混乱 不记录当前层节点数 level_size控制每层遍历次数
4. 空树边界 忘记处理空列表 入口处判断if not inorder: return None

核心口诀

后序找根,中序分边,先右后左,重建完成

相关推荐
m0_674294642 小时前
C#怎么使用Channel异步通道 C#如何用BoundedChannel实现有界队列限流异步数据流【进阶】
jvm·数据库·python
m0_748920362 小时前
HTML函数在系统更新后变卡是硬件老化吗_软硬兼容性排查【方法】
jvm·数据库·python
23471021272 小时前
4.20 学习笔记
软件测试·笔记·python·学习
weixin_424999362 小时前
如何正确对对象键名进行字母序排序并存入数组
jvm·数据库·python
生信研究猿2 小时前
ACM格式:在pycharm输入
python
maqr_1102 小时前
如何配置Oracle 19c审计清理_DBMS_AUDIT_MGMT自动清除策略
jvm·数据库·python
qq_372906932 小时前
如何用 JavaScript 实现单选式盒子颜色切换(点击高亮,其余复原)
jvm·数据库·python
2401_897190552 小时前
怎样使用Navicat高级特权进行还原时解决字符集冲突_企业数据保护
jvm·数据库·python
木子墨5162 小时前
LeetCode 热题 100 精讲 | 计算几何篇:点积叉积 · 线段相交 · 凸包 · 多边形面积
c++·算法·leetcode·职场和发展·动态规划
weixin_580614002 小时前
c++文件锁使用方法 c++如何实现多进程文件同步
jvm·数据库·python