在学习和使用数据结构时,二叉树是最基础、也最容易考察的结构之一。而遍历方式,则是二叉树应用的入口。所谓「遍历」,是指按照某种规则,依次访问树中的每一个节点。而在众多遍历方式中,前序、中序、后序遍历是最经典、最基础、也最常用的三种。
本文将围绕这三种遍历方式,讲清楚如下几个问题:
-
它们各自的定义和特点是什么?
-
如何用递归与非递归两种方式实现?
-
它们分别在工程中能干什么?
-
实战题型:如何识别遍历顺序?如何用遍历序列还原树结构?
目录
二叉树的结构回顾
一个二叉树(Binary Tree)的每个节点至多有两个子节点,分别称为左子树和右子树。用代码表示通常是这样的结构:
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
我们将从根节点出发,按照不同顺序访问子节点,就得到了不同的遍历方式。
三种遍历的定义
-
前序遍历(Pre-order):根节点 → 左子树 → 右子树
-
中序遍历(In-order):左子树 → 根节点 → 右子树
-
后序遍历(Post-order):左子树 → 右子树 → 根节点
以图中二叉树为例:遍历结果如下:
-
前序遍历:A B D E C F
-
中序遍历:D B E A C F
-
后序遍历:D E B F C A
递归实现:最简单但最易混淆的方法
递归是实现树遍历最直接的方式,因为树结构天然是递归结构。
def preorder(root):
if root:
print(root.val)
preorder(root.left)
preorder(root.right)
def inorder(root):
if root:
inorder(root.left)
print(root.val)
inorder(root.right)
def postorder(root):
if root:
postorder(root.left)
postorder(root.right)
print(root.val)
非递归实现:堆栈模拟调用过程
前序遍历(非递归)
def preorder_iterative(root):
if not root:
return
stack = [root]
while stack:
node = stack.pop()
print(node.val)
if node.right:
stack.append(node.right)
if node.left:
stack.append(node.left)
中序遍历(非递归)
def inorder_iterative(root):
stack = []
node = root
while stack or node:
while node:
stack.append(node)
node = node.left
node = stack.pop()
print(node.val)
node = node.right
后序遍历(非递归)这是最难的一个,我们可以借助两个栈,或者使用标记法:
def postorder_iterative(root):
if not root:
return
stack = [root]
out = []
while stack:
node = stack.pop()
out.append(node.val)
if node.left:
stack.append(node.left)
if node.right:
stack.append(node.right)
for val in reversed(out):
print(val)
工程应用场景与典型题型
前序遍历的常用场景
-
导出目录结构(根节点先输出)
-
树结构序列化:先根,再子树,可以方便记录结构
中序遍历的常用场景
-
二叉搜索树(BST)中序遍历即为升序排列
-
应用于平衡检查、区间查找等功能
后序遍历的常用场景
-
节点释放、后序处理(如计算子树大小)
-
编译器抽象语法树(先处理子表达式)
还原树结构
给定中序遍历 + 前序/后序,可以唯一确定一棵二叉树
例如 前序 + 中序重建二叉树:
def buildTree(preorder, inorder):
if not preorder:
return None
root = TreeNode(preorder[0])
idx = inorder.index(root.val)
root.left = buildTree(preorder[1:idx+1], inorder[:idx])
root.right = buildTree(preorder[idx+1:], inorder[idx+1:])
return root
常见问题
常见问题 | 原因 | 解决方式 |
---|---|---|
遍历顺序写错 | 递归调用顺序不对 | 手写遍历过程画图推导 |
非递归实现死循环 | 栈控制不当 | 使用断点调试打印 stack 变化 |
子树为空时出错 | 没有判断 None | 所有递归边界加 if not root: 检查 |
多个节点值相同 | 使用 index() 找不到正确位置 | 改为使用值 → 下标的字典 |