本讲定位:单选第 12 题固定考「层序遍历的变体填空」——2026 年 6 月和 2026 年 3 月连续两次都是二叉树的右视图,2025 年 12 月是「普通二叉树里 BFS 找值」。加上单选第 6 题(用 BFS 判完全二叉树,六级第 03 讲已讲)和 1~2 道判断题,本讲覆盖 6~8 分。
BFS 和上一讲的 DFS 是一对:DFS 用栈往深处钻,BFS 用队列一层一层扫。六级第 01 讲的队列、六级第 02 讲的层序遍历,在这一讲合流成一个通用模板。
对应官方大纲:六级知识块 3「搜索算法」——宽度优先搜索算法(BFS)、二叉树的搜索算法。
前置知识:六级第 01 讲(队列)、六级第 02 讲(层序遍历)、六级第 05 讲(DFS)。
代码说明:本讲代码均已用 g++ 11.5(
-std=c++11)编译运行验证;右视图程序与「DFS 先右后左记录每层首次到达」的独立实现对拍 500 组随机树。
$$ \boxed{\textbf{先把身边的都看一遍,再往外扩一圈;一层一层地扫}} $$
和 DFS 的对照——这张表要背:
| DFS | BFS | |
|---|---|---|
| 策略 | 一条路走到底 | 一层一层往外扩 |
| 容器 | 栈(或递归) | 队列 |
| 访问顺序 | 深度优先 | 由近及远 |
| 空间 | $O(树高)$ | $O(最宽一层的结点数)$ |
| 擅长 | 子树统计、枚举所有方案 | 最短路(步数最少)、按层处理 |
⚠️⚠️ 判断题头号考点(2025 年 12 月六级判断第 4 题,官方答案「错」):「广度优先遍历二叉树可用栈来实现」——不能。
理由:BFS 要求「先发现的先处理」,这正是队列的行为。换成栈就变成「后发现的先处理」,遍历顺序会退化成深度优先的样子。
反过来 DFS 可以用栈(六级第 02 讲第 3.4 节写过)。口诀:BFS 只能用队列,DFS 栈和递归都行。
六级第 02 讲写过基础版,这里把带层号的通用模板固定下来。本讲所有变体都是在这个模板里改一行。
#include<iostream>
#include<queue>
#include<vector>
using namespace std;
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
// 建一棵固定的测试树,后面反复用
// 1
// ┌──┴──┐
// 2 3
// ┌─┴─┐ └─┐
// 4 5 6
// ┌┘
// 7
TreeNode* buildDemo() {
TreeNode* root = new TreeNode(1);
root->left = new TreeNode(2);
root->right = new TreeNode(3);
root->left->left = new TreeNode(4);
root->left->right = new TreeNode(5);
root->right->right = new TreeNode(6);
root->left->right->left = new TreeNode(7);
return root;
}
void levelOrder(TreeNode* root) {
if (!root) return;
queue<TreeNode*> q;
q.push(root);
int level = 0;
while (!q.empty()) {
int sz = q.size(); // ★★ 必须先量长度
level++;
cout << "第 " << level << " 层: ";
for (int i = 0; i < sz; ++i) { // 这一层恰好 sz 个
TreeNode* cur = q.front();
q.pop();
cout << cur->val << " ";
if (cur->left) q.push(cur->left);
if (cur->right) q.push(cur->right);
}
cout << endl;
}
}
int main() {
levelOrder(buildDemo());
return 0;
}
输出:
| 层 | 结点 |
|---|---|
| 第 1 层 | 1 |
| 第 2 层 | 2 3 |
| 第 3 层 | 4 5 6 |
| 第 4 层 | 7 |
(实测验证 ✅)
int sz = q.size();2026 年 6 月六级判断第 8 题(官方答案「错」) 给的就是下面这个写法:
while (!q.empty()) {
for (int i = 0; i < q.size(); ++i) { // ← 错在这里
TreeNode* cur = q.front();
q.pop();
cout << cur->val << " ";
if (cur->left) q.push(cur->left);
if (cur->right) q.push(cur->right);
}
cout << endl;
}
问题出在:循环体里既 pop 又 push,q.size() 一直在变,而 i < q.size() 每一轮都要重新求值,于是「这一层有几个」的边界就完全失控了。
用上面那棵测试树实测,两个版本的对比: