C++实现二叉树的宽度优先搜索BFS _ 队列与层级记录【源码】

雨枫大大_5257

雨枫大大_5257

2026-04-13

276人浏览

原创

std::queue是bfs最自然的选择,因其fifo特性完美匹配“逐层扩展”逻辑;需用q.size()冻结每层节点数以保层级信息,访问treenode指针前必须判空防崩溃。

c++实现二叉树的宽度优先搜索bfs _ 队列与层级记录【源码】

为什么 std::queue 是 BFS 最自然的选择

因为 BFS 本质就是“一层层往外扩”,而队列的 FIFO 特性天然匹配这个过程:先入队的节点,一定先被访问、先扩展子节点。用栈或 vector 模拟反而容易错乱层级顺序。

常见错误是把 root 入队后,直接 while (!q.empty()) { auto n = q.front(); q.pop(); ... } 就完事——这样能遍历所有节点,但**完全丢失层级信息**,无法回答“第 k 层有哪些节点”或“每层最大值是多少”这类问题。

实操建议:

C++ Code Review Master
C++ Code Review Master

组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。

下载
  • 始终用 std::queue<treenode></treenode>(指针,避免拷贝树节点)
  • 每次循环开始前,用 q.size() 记录当前层节点数,再循环 pop 这么多次,确保“处理完一层才进下一层”
  • 不要在循环中动态修改 q.size() 的判断依据(比如写成 i 且在循环内 push —— <code>size() 会变,导致逻辑错乱)

如何正确记录每一层的节点值(含空节点处理)

很多实现只存非空子节点,导致层级对齐失败;但若严格按满二叉树补 nullptr,又浪费空间。实际取舍取决于需求:

如果目标是打印层级结构(如 LeetCode 的 levelOrder),只需保存非空节点;如果要做“之字形遍历”或“检查是否为完全二叉树”,就得显式处理空位。

实操建议:

  • 标准层级遍历(忽略空节点):只对 node->left 和 node->right 非空时才 push
  • 需要空占位时:在每层末尾不补空,而是在子节点入队前统一判断,if (node) { q.push(node->left); q.push(node->right); } else { q.push(nullptr); q.push(nullptr); } —— 但注意这会导致无限 nullptr,必须加层数限制或空节点计数终止
  • 更稳妥的做法是用两个队列轮换,或用 pair 存 {node, level},避免歧义

TreeNode 结构定义与空指针安全访问

标准 TreeNode 定义里 left 和 right 是裸指针,BFS 过程中任何一次解引用都可能 crash。尤其在调试时临时插入 cout val 却忘了判空,就会触发 segmentation fault。

实操建议:

  • 定义时明确初始化: TreeNode() : val(0), left(nullptr), right(nullptr) {}
  • 每次访问 node->left 或 node->val 前,先写 if (!node) continue;(放在循环开头比分散判空更可靠)
  • 用智能指针(如 std::unique_ptr<treenode></treenode>)可提升安全性,但 LeetCode 等平台输入固定为裸指针,实际项目中才建议切换
  • 错误现象示例:member access within null pointer of type 'struct TreeNode' —— 这是编译器(如 clang)的 UB 提示,说明你解引用了 nullptr

完整可运行的层级遍历代码(带注释)

以下是最简可用版本,返回二维 vector,每行是一个层级的节点值:

vector<vector>> levelOrder(TreeNode* root) {
    vector<vector>> res;
    if (!root) return res;
<pre class="brush:php;toolbar:false;">queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
    int levelSize = q.size(); // 关键:冻结当前层宽度
    vector<int> level;
    for (int i = 0; i < levelSize; ++i) {
        TreeNode* node = q.front();
        q.pop();
        level.push_back(node->val);
        if (node->left)  q.push(node->left);
        if (node->right) q.push(node->right);
    }
    res.push_back(level);
}
return res;

}

注意 levelSize 必须在 for 循环外获取,且不能写成 for (int i = 0; i —— 因为循环体内 <code>push 会让 q.size() 动态增长,导致多处理下一层的节点。

真正容易被忽略的是:当树极深时,queue 的内存占用是 O(w),w 是最大层宽,不是树高。对倾斜树(如只有右链),BFS 的空间开销反而比 DFS 小;但对满二叉树,BFS 在最后一层会存下 ~n/2 个节点,务必确认内存约束。

C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

c++

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

2023.09.22

549

3

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

2024.03.01

1678

6

while的用法
while的用法

while的用法是“while 条件: 代码块”,条件是一个表达式,当条件为真时,执行代码块,然后再次判断条件是否为真,如果为真则继续执行代码块,直到条件为假为止。本专题为大家提供while相关的文章、下载、课程内容,供大家免费下载体验。

2023.09.25

354

5

java break和continue
java break和continue

本专题整合了java break和continue的区别相关内容,阅读专题下面的文章了解更多详细内容。

2025.10.24

747

6

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.02

6059

3

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.08.29

2965

6

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

2025.08.29

3788

10

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

2025.08.29

2645

10

C++ 智能指针与现代内存管理
C++ 智能指针与现代内存管理

深入讲解 C++ 现代内存管理的核心工具——智能指针,涵盖 unique_ptr 独占所有权语义、shared_ptr 引用计数机制与循环引用问题、weak_ptr 弱引用的应用场景、make_unique/make_shared 工厂函数的性能优势、自定义删除器的编写、RAII 资源管理思想的实践,以及从裸指针迁移到智能指针的重构策略,帮助开发者编写安全无泄漏的现代 C++ 代码。

2026.04.23

339

31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C++ Core Guidelines
C++ Core Guidelines

共0课时 | 0人学习

C++ Reference
C++ Reference

共0课时 | 0人学习

C++ 官方标准说明
C++ 官方标准说明

共0课时 | 0人学习