1. 前言
二叉树(Binary Tree)是数据结构中最重要的非线性结构之一。掌握二叉树的遍历方法是算法学习的基础,本文将全面讲解四种经典遍历方式:
-
层次遍历(Level Order)
-
先序遍历(PreOrder)
-
中序遍历(InOrder)
-
后序遍历(PostOrder)
通过清晰的代码实现和示意图,帮助读者彻底理解它们的区别与应用场景。
2. 二叉树结构定义
typedef struct BiTNode {
int data;
struct BiTNode *lchild, *rchild;
} BiTNode, *BiTree;
3. 四种遍历方式详解
(1)层次遍历(Level Order)
特点:按层级从上到下、从左到右访问节点
应用:求树的高度、打印树结构
实现:需借助队列
void LevelOrder(BiTree T) {
if (T == NULL) return;
LinkQueue Q;
InitQueue(Q);
EnQueue(Q, T);
BiTree p;
while (!IsEmpty(Q)) {
DeQueue(Q, p);
visit(p);
if (p->lchild) EnQueue(Q, p->lchild);
if (p->rchild) EnQueue(Q, p->rchild);
}
}
示例:
1
/ \
2 3
输出:1 2 3
(2)先序遍历(PreOrder)
特点:根 → 左子树 → 右子树
应用:复制二叉树、前缀表达式
递归实现:
void PreOrder(BiTree T) {
if (T != NULL) {
visit(T); // 访问根
PreOrder(T->lchild); // 左子树
PreOrder(T->rchild); // 右子树
}
}
非递归实现(需栈):
void PreOrder_NonRecursive(BiTree T) {
stack<BiTree> s;
BiTree p = T;
while (p || !s.empty()) {
if (p) {
visit(p);
s.push(p);
p = p->lchild;
} else {
p = s.top();
s.pop();
p = p->rchild;
}
}
}
示例:
输出:1 2 3
(3)中序遍历(InOrder)
特点:左子树 → 根 → 右子树
应用:二叉搜索树排序
递归实现:
void InOrder(BiTree T) {
if (T != NULL) {
InOrder(T->lchild); // 左子树
visit(T); // 访问根
InOrder(T->rchild); // 右子树
}
}
非递归实现:
void InOrder_NonRecursive(BiTree T) {
stack<BiTree> s;
BiTree p = T;
while (p || !s.empty()) {
if (p) {
s.push(p);
p = p->lchild;
} else {
p = s.top();
visit(p);
s.pop();
p = p->rchild;
}
}
}
示例:
输出:2 1 3
(4)后序遍历(PostOrder)
特点:左子树 → 右子树 → 根
应用:释放二叉树内存、后缀表达式
递归实现:
void PostOrder(BiTree T) {
if (T != NULL) {
PostOrder(T->lchild); // 左子树
PostOrder(T->rchild); // 右子树
visit(T); // 访问根
}
}
非递归实现(需双栈):
void PostOrder_NonRecursive(BiTree T) {
stack<BiTree> s1, s2;
s1.push(T);
while (!s1.empty()) {
BiTree p = s1.top();
s1.pop();
s2.push(p);
if (p->lchild) s1.push(p->lchild);
if (p->rchild) s1.push(p->rchild);
}
while (!s2.empty()) {
visit(s2.top());
s2.pop();
}
}
示例:
输出:2 3 1
4. 四种遍历对比
遍历方式 | 访问顺序 | 应用场景 | 实现难度 |
---|---|---|---|
层次遍历 | 按层级 | 打印树结构、BFS | 中等 |
先序遍历 | 根 → 左 → 右 | 复制树、前缀表达式 | 简单 |
中序遍历 | 左 → 根 → 右 | 二叉搜索树排序 | 简单 |
后序遍历 | 左 → 右 → 根 | 释放内存、后缀表达式 | 较难 |
5. 完整测试代码
#include <iostream>
#include <stack>
#include <queue>
using namespace std;
// 二叉树节点定义
typedef struct BiTNode {
int data;
struct BiTNode *lchild, *rchild;
} BiTNode, *BiTree;
// 初始化二叉树
BiTree CreateTree() {
BiTree root = new BiTNode{1, NULL, NULL};
root->lchild = new BiTNode{2, NULL, NULL};
root->rchild = new BiTNode{3, NULL, NULL};
return root;
}
// 访问节点
void visit(BiTree p) {
cout << p->data << " ";
}
// 先序遍历(递归)
void PreOrder(BiTree T) {
if (T) {
visit(T);
PreOrder(T->lchild);
PreOrder(T->rchild);
}
}
// 中序遍历(递归)
void InOrder(BiTree T) {
if (T) {
InOrder(T->lchild);
visit(T);
InOrder(T->rchild);
}
}
// 后序遍历(递归)
void PostOrder(BiTree T) {
if (T) {
PostOrder(T->lchild);
PostOrder(T->rchild);
visit(T);
}
}
// 层次遍历(队列)
void LevelOrder(BiTree T) {
if (!T) return;
queue<BiTree> q;
q.push(T);
while (!q.empty()) {
BiTree p = q.front();
q.pop();
visit(p);
if (p->lchild) q.push(p->lchild);
if (p->rchild) q.push(p->rchild);
}
}
int main() {
BiTree root = CreateTree();
cout << "先序遍历: ";
PreOrder(root); // 1 2 3
cout << "\n中序遍历: ";
InOrder(root); // 2 1 3
cout << "\n后序遍历: ";
PostOrder(root); // 2 3 1
cout << "\n层次遍历: ";
LevelOrder(root); // 1 2 3
return 0;
}
6. 常见问题
Q1: 非递归实现为什么需要栈?
-
答:递归本质是栈操作,非递归需用显式栈模拟递归过程。
Q2: 如何选择遍历方式?
-
若需层级操作 → 层次遍历
-
若需父节点优先 → 先序遍历
-
若需排序结果(BST)→ 中序遍历
-
若需子节点优先 → 后序遍历
7. 总结
-
层次遍历:队列实现,BFS经典应用。
-
先/中/后序遍历:递归或栈实现,区别仅在于访问根的时机。
-
非递归实现:建议掌握,面试高频考点。