102. 二叉树的层序遍历 
题目描述
给定二叉树根节点 root,按从上到下、从左到右的顺序返回每一层的节点值。
题型判断
题目要求把节点“按层”分组返回,这是 BFS 的典型信号。
层序遍历的关键不是单纯遍历所有节点,而是要知道每一层的边界在哪里。因此在处理某一层之前,需要先记录当前队列中属于这一层的节点数量 levelSize。
核心思路
- 空树直接返回空数组。
- 根节点入队。
- 进入每一层时,固定当前层节点数
levelSize。 - 保存节点值,并将左右孩子加入队尾。
- 本层处理完后,把结果加入答案。
这里的队列示意表示“当前待处理的节点”。代码实现中使用 head 指针模拟出队,所以数组里已经访问过的节点不会立刻删除。
代码实现
head 表示当前队头位置,每处理一个节点就向后移动一位。这样可以避免使用 shift(),因为 JavaScript 数组从头部删除元素可能触发整体搬移。
另一种写法:每层重置队列
也可以在每一层开始时保存当前队列,然后把 queue 重置为空数组,专门收集下一层节点。这样不需要维护 head 和 levelSize:
这里 currentLevel 保存当前层,重置后的 queue 只保存下一层。不能一边遍历同一个 queue,一边向其中加入子节点,最后再清空,否则当前层和下一层的节点会混在一起。
这种写法同样不会调用 shift(),所以每个节点仍然只会被处理一次。遍历过程中可能同时存在当前层和下一层两个数组,但它们保存的节点引用总数仍然与树的最大宽度同阶,因此辅助空间复杂度为 O(w);最坏情况下 w = O(n)。它的代价是每层都会创建一个新数组。
复杂度分析
-
时间复杂度:
O(n),每个节点入队、出队各一次。 -
空间复杂度:
O(n)。当前实现用
head指针模拟出队,queue中访问过的节点不会被删除,最坏情况下会保存所有节点。如果使用真正的队列结构,只看遍历过程中的待处理节点,辅助空间可以理解为O(w),其中w是二叉树的最大宽度。计入返回结果时一定是O(n)。按层重置队列的写法只保留当前层和下一层,辅助空间为
O(w),最坏情况下也是O(n)。如果计入返回结果,空间复杂度同样为O(n)。
边界与易错点
- 空树返回
[],不是[[]]。 levelSize要在进入内层循环前固定。- 不建议使用
shift()出队;JavaScript 数组头删可能产生O(n)的元素移动。 - 使用
head指针时,循环条件应该是head < queue.length,不能只判断queue.length > 0。 - 只有一个根节点时,返回
[[root.val]]。 - 链状二叉树也可以正常处理,只是每一层只有一个节点。

