二叉树的层序遍历 图解题解
队列能访问所有节点,但怎么知道哪到哪是同一层?
工厂流水线按批次发货:一批发出去,才确认下一批数量。层序遍历也这样——每次进 while 循环先拍个「快照」,记下此刻队列里有多少个节点,这就是本层的全部;只处理这么多,处理时顺手把孩子推进队列;这批处完,队列里新攒的恰好是下一整层,再次快照、再次处理。层与层之间从不混淆。
这道题到底在问什么
- 输入
- 上图这棵 12 节点树
- 输出
- [[1],[2,3],[4,5,6,7],[8,9,10,11,12]]
最优解:为什么这么做
一句话答案:LeetCode 102 二叉树的层序遍历用队列做 BFS:根先入队,每轮循环开始时记下队列当前长度,恰好出队这么多个节点组成一层,出队时把非空孩子入队。先进先出保证层内从左到右、层与层不串。每个节点入队出队各一次,时间 O(n),空间 O(n)。
层序遍历要的输出长什么样
题目要求从根开始逐层访问二叉树,每层内部从左到右,并且结果要按层分组——返回的是「数组的数组」,第 k 个子数组装第 k 层所有节点的值。这个「分组」要求是本题的真正考点:单纯把节点按层的顺序吐出来不难,难的是准确知道每一层在哪里结束。
为什么层序遍历用队列而不是递归
深度优先的递归天生「一条道走到黑」,先扎进左子树最深处才回头,访问顺序和按层完全拧着。而层序遍历的本质是广度优先搜索(BFS):先处理离根近的,再处理离根远的。队列的先进先出恰好维护这个次序——根先入队;每出队一个节点,就把它的左右孩子(下一层)追加到队尾。第 k 层的节点总比第 k+1 层的先进队,也就总被先处理,逐层推进不需要任何额外排序。
顺带一提,同层从左到右也是队列天然保证的:父节点按左到右出队,各自的孩子也按左到右入队,顺序全程保持。换成栈就成了后进先出,直接退化回深度优先。
怎么知道一层在哪里结束
关键技巧是在处理每一层之前,先把队列当前的长度记下来,记作 sz。此时有一个不变量成立:队列里恰好装着当前层的全部节点、且只有当前层的。于是接下来只出队 sz 个,出来的必然正好是这一层;过程中入队的孩子全属于下一层,它们排在队尾、这一轮碰不到。sz 个处理完,不变量对下一层重新成立,循环继续。
如果不先锁定 sz,直接写 while 循环边出队边入队,队列长度在循环中不断变化,就再也分不清谁是哪层的——这是本题第一大错误写法。
每个细节为什么这样写
根为空要先返回空数组,否则空树入队会立刻出错。孩子入队前必须判非空:把 null 塞进队列,下一轮出队时要么崩溃、要么污染下一层的结果。循环的终止也很自然——最底层都是叶子,没有新节点入队,队列耗空,while 结束,所有层恰好各归其位。
复杂度怎么数,还能怎么变形
时间 O(n):每个节点恰好入队一次、出队一次,每次操作 O(1)。空间 O(n):队列的峰值出现在最宽的一层,完全二叉树的最底层约有 n/2 个节点,量级就是 O(n)。
这套「锁层长的 BFS」是一批题的公共骨架:之字形层序(LeetCode 103)只需把偶数层的结果反转;求每层最大值、右视图等也都是在「一层一组」这个结构上做文章。骨架写熟,这些变形都是一两行的改动。
▶ 动画逐步走查(共 25 步)——想跟着动画一帧帧对照就展开
- 3记住这条:出队一个、孩子入队,队列自动帮你一层一层往下推。
- 4根节点入队。出队一个、把它的孩子入队,队列天然按层推进。
- 5出队 1:加入第 1 层结果。出队一个、把它的孩子入队,队列天然按层推进。
- 61 的孩子 2 入队。出队一个、把它的孩子入队,队列天然按层推进。
- 71 的孩子 3 入队。第 1 层扫完:[1]——队列里现在全是下一层节点,继续。
- 8出队 2:加入第 2 层结果。出队一个、把它的孩子入队,队列天然按层推进。
- 92 的孩子 4 入队。出队一个、把它的孩子入队,队列天然按层推进。
- 102 的孩子 5 入队。出队一个、把它的孩子入队,队列天然按层推进。
- 11出队 3:加入第 2 层结果。出队一个、把它的孩子入队,队列天然按层推进。
- 123 的孩子 6 入队。出队一个、把它的孩子入队,队列天然按层推进。
- 133 的孩子 7 入队。第 2 层扫完:[2, 3]——队列里现在全是下一层节点,继续。
- 14出队 4:加入第 3 层结果。出队一个、把它的孩子入队,队列天然按层推进。
- 154 的孩子 8 入队。出队一个、把它的孩子入队,队列天然按层推进。
- 164 的孩子 9 入队。出队一个、把它的孩子入队,队列天然按层推进。
- 17出队 5:加入第 3 层结果。出队一个、把它的孩子入队,队列天然按层推进。
- 185 的孩子 10 入队。出队一个、把它的孩子入队,队列天然按层推进。
- 195 的孩子 11 入队。出队一个、把它的孩子入队,队列天然按层推进。
- 20出队 6:加入第 3 层结果。出队一个、把它的孩子入队,队列天然按层推进。
- 216 的孩子 12 入队。出队一个、把它的孩子入队,队列天然按层推进。
- 22出队 7:加入第 3 层结果。第 3 层扫完:[4, 5, 6, 7]——队列里现在全是下一层节点,继续。
- 23出队 8:加入第 4 层结果。出队一个、把它的孩子入队,队列天然按层推进。
- 24出队 9:加入第 4 层结果。出队一个、把它的孩子入队,队列天然按层推进。
- 25出队 10:加入第 4 层结果。出队一个、把它的孩子入队,队列天然按层推进。
- 26出队 11:加入第 4 层结果。出队一个、把它的孩子入队,队列天然按层推进。
- 27出队 12:加入第 4 层结果。第 4 层扫完:[8, 9, 10, 11, 12]——叶子层没有新节点进队,队列已经为空,循环结束。
⚠️ 容易写错的地方
✗ 错:不锁本层个数
✓ 对:进 for 前先存 sz=q.size()
循环里队列在变长,分不出层
✗ 错:忘判空根
✓ 对:root 为空直接返回 []
否则空树会越界
✗ 错:左右孩子漏判 null
✓ 对:只把非空孩子入队
null 入队会污染下一层
完整代码(Python / Java / C++)
Python
def levelOrder(root):
if not root: return []
res, q = [], deque([root])
while q:
level = []
for _ in range(len(q)): # 锁定本层个数
node = q.popleft() # 出队一个
level.append(node.val)
if node.left: q.append(node.left) # 孩子入队
if node.right: q.append(node.right)
res.append(level)
return resJava
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
if (root == null) return res;
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
while (!q.isEmpty()) {
int sz = q.size(); // 锁定本层个数
List<Integer> level = new ArrayList<>();
for (int i = 0; i < sz; i++) {
TreeNode node = q.poll(); // 出队一个
level.add(node.val);
if (node.left != null) q.offer(node.left); // 孩子入队
if (node.right != null) q.offer(node.right);
}
res.add(level);
}
return res;
}C++
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> res;
if (!root) return res;
queue<TreeNode*> q; q.push(root);
while (!q.empty()) {
int sz = q.size(); // 锁定本层个数
vector<int> level;
for (int i = 0; i < sz; ++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;
}复杂度
时间
O(n)
每个节点恰好入队、出队各一次
空间
O(n)
队列最多装下最宽一层的节点
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 二叉树的层序遍历 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
为什么用队列而不是栈?+
队列先进先出,保证同一层的节点按入队顺序(左到右)被处理;栈是后进先出,会变成深度优先。
怎么做「锯齿层序」(之字形)?+
同样的 BFS,只在偶数层把该层结果 reverse 一下,或用双端队列控制方向。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄把 二叉树的层序遍历 一步步讲透(全站已上线 905 份讲透,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。