二叉树层级扫描本质是按层推进的广度优先遍历,关键靠levelSize快照当前队列长度以隔离每层节点,队列仅存TreeNode引用,每轮外层循环生成一个子列表,空树或单节点均适用同一逻辑。
二叉树层级扫描本质是按层推进的广度优先遍历(bfs),核心不在“遍历”本身,而在如何精准识别和隔离每一层的数据边界。变量处理逻辑是否清晰,直接决定结果能否正确分组——比如输出 [[3], [9,20], [15,7]] 而不是扁平的 [3,9,20,15,7]。
关键变量:levelSize 控制单层处理范围
每次进入外层循环前,必须记录当前队列长度,即本层节点总数:
- levelSize = queue.size() 是不可省略的快照操作,它冻结了“此刻该处理多少个节点”
- 内层循环严格执行 levelSize 次出队,哪怕过程中已把下一层子节点加入队列,也不会干扰本轮计数
- 若跳过这一步,仅用
while(!queue.isEmpty()),就会混入下一层节点,导致层级坍塌
队列操作:只存节点引用,不存层级信息
标准实现中,队列里只放 TreeNode 对象,不额外携带层数或标记。层级信息完全由 levelSize 和出入队节奏隐式表达:
- 根节点入队 → 队列含 1 个节点 →
levelSize = 1→ 处理 1 次,同时将它的左右子节点(若有)入队 - 第二轮开始时,队列中恰好是第二层全部节点 →
levelSize自动等于该层数量 - 左子节点总在右子节点之前入队,天然保证每层内部从左到右顺序
结果收集:每轮内层循环生成一个独立子列表
层级分组不是靠判断节点值,而是靠处理节奏:
- 每轮外层循环对应一层,新建一个空列表
levelList = new ArrayList<>() - 内层循环中,每次出队一个节点,将其值加入
levelList - 内层循环结束,
levelList就是完整的一层数据,追加进最终结果res - 无需判断是否为叶子、是否为空,逻辑对所有节点一视同仁
边界处理:空树与单节点也适用同一逻辑
初始化阶段统一判空,后续流程保持一致:
- 若
root == null,队列始终为空,外层循环不执行,直接返回空结果 - 若只有根节点,
levelSize = 1,内层循环执行一次,输出[[root.val]] - 所有分支逻辑(左子、右子是否存在)都在出队后即时检查,不提前预判

















