← 树 · 遍历、平衡 BST 与前缀 / 度量树 / 层序:用队列逐层从左到右 待审核 4 / 10
层序 BFS · 用队列逐层

层序:用队列逐层从左到右

前 / 中 / 后序都属深度优先 (DFS)——一头扎到底再回头,靠(后进先出)记回头路。层序遍历 (level-order) 是另一族:广度优先 (BFS),先访问根,再访问第 1 层全部、第 2 层全部……逐层铺开、每层从左到右。它不靠栈,而靠一个队列(FIFO,先进先出):出队一个就访问它,再把它的左、右子排到队尾等下一层处理。把「栈」换成「队列」,深度优先就变成了广度优先。

本页约定: 演示树是二叉搜索树 (BST)。当前出队 / 正在访问的节点 node橙色描边;刚入队的子节点用粉色描边;已访问节点填实心青色。下方队列横条:最左 = 队首(下一个出队),最右 = 队尾(刚入队)。输出区按分组,直观呈现 BFS 的逐层结构。

1 · 队列 vs 栈:一字之差,深度变广度

BFS 的代码和前序迭代几乎一模一样,唯一的差别是取出元素的那一端:前序迭代从容器尾部取(栈,后进先出),于是一头扎进最新压入的子树——深度优先;层序从容器头部取(队列,先进先出),于是先把同层的兄弟全访问完才下沉——广度优先。同样的「出队即访问、子节点入容器」骨架,换一种容器就换了一族遍历。

###「按层 size 快照」:怎么知道一层到哪结束

队列里随时混着相邻两层的节点,怎么切分出「一层」?技巧是:每进入新一层的循环前,先记下此刻队列长度 size。因为上一层的节点都已出队、它们的子(即这一整层)刚好都已入队,所以这个 size 精确等于当前层的节点数。接着只循环 size 次,就恰好处理完整层、不会越界到下一层。本页输出区就靠它分组。若不需要分层、只要一条扁平序列,去掉这层 for、直接 while queue 即可。

1.1 · 要「自底向上」层序 (LC 107):正着收集,最后翻一次层序

有时需求是最后一层在前、根在后(层内仍从左到右),即 Binary Tree Level Order Traversal II。不必改遍历方向:照本页正常自顶向下 BFS 逐层收集成 levels=[L0,L1,L2,]levels = [L0, L1, L2, \dots ],最后把这个层数组整体 reverse 一次 (return levels[::-1]) 即可。关键是只翻外层(层与层之间),每层内部 [a, b, c] 一个都不动。等价写法是每收完一层 insert(0, level) 插到队头,但那是 O(层数)的搬移,不如末尾一次性 reverse() 干净。若要的是整条扁平序列彻底倒序(末节点→首节点、层内也从右到左),那是另一回事:把扁平 output 直接 [::-1],或遍历时右子先入队、左子后入队再翻层序。

层序的额外空间是 O(w),不是 O(h)。 DFS(递归 / 栈)的峰值空间是树 h;BFS 队列的峰值是树最宽一层的宽度 w。对一棵满二叉树,最后一层就有约 n/2 个节点,故 w 可达 O(n)——层序在「矮而宽」的树上反而比 DFS 更耗内存。选 DFS 还是 BFS,取决于你要的访问次序与树的形状