(e4)层次遍历

官官方信息技术老师·12 页·深入(追求细节与边界)·0 次浏览·38 天前
数据结构二叉树队列BFS

二叉树的层次遍历

看完你能说清遍历次序、写出队列实现、并算清每层边界

按 空格/→ 演示下一步

问一句
1 / 12 页

全部页面点击任意一页,跳回舞台从这页播放

数据结构二叉树队列BFS

二叉树的层次遍历

看完你能说清遍历次序、写出队列实现、并算清每层边界

1第 1 页 · 二叉树的层次遍历

什么是「按层」访问

公司开大会前,主持人不会逮着谁叫谁,而是先请 CEO 层的几位,再请总监层,最后到员工层——一层一层点名,这就是按层访问的直觉。

逐层推进
先访问完第 1 层全部节点,再进入第 2 层
层内有序
同一层内按从左到右的顺序依次访问
不回头
每层只走一遍,访问过不再重复
公司组织架构点名对应 →层次遍历

CEO 层对应根节点层,逐级下属对应逐层子树

2第 2 页 · 什么是「按层」访问

次序规则:自上而下、从左到右

图中标注了每个节点的访问序号:先标根,再逐层从左往右依次编号,跟着序号走一遍。

图解渲染中…
a1:字母为节点值,数字为访问顺序编号d1:最深层的 H 排最后,体现自上而下
3第 3 页 · 次序规则:自上而下、从左到右

层次遍历 vs 深度优先遍历

都叫「遍历」,但先/中/后序走的是纵向路径,层次遍历走横向——方向不同,访问顺序完全不同。

深度优先(先/中/后序)
  • 沿一条分支走到底再回头,纵向推进
  • 用递归或栈,靠函数调用深度实现
  • 先/中/后序差异在根的访问时机
层次遍历
  • 按层横向推进,逐层完整覆盖
  • 用队列,先进先出保证层内顺序
  • 不存在先/中/后之分,只有一种顺序
需要按深度处理或释放整棵树时选深度优先;需要逐层处理(如求层高、最短层)时选层次遍历。
4第 4 页 · 层次遍历 vs 深度优先遍历

为什么递归不管用,队列登场

上一页我们看到:深度优先会一头扎到底,访问顺序和「按层」完全对不上。问题出在哪?深度优先靠递归,本质是栈——后进先出。而逐层访问需要的是先进先出,这正好是队列的脾气。

递归=栈
函数调用天然后进先出,最深节点先被处理,无法保证同层顺序
层次需要FIFO
先入队的层先出队访问,先进先出恰好匹配自上而下
队列的用法
出队一个节点,就把它的左右孩子依次入队,层序自然延续
食堂排队打饭对应 →队列式层次遍历

先排队的人先打饭,对应先入队的节点先被访问

5第 5 页 · 为什么递归不管用,队列登场

算法流程:入队、出队、带娃

层次遍历的循环就三个动作:出队、访问、把孩子押进队列。

1
队首出队
取出队首节点,它就是当前这一步要处理的节点
2
访问节点
立刻处理该节点的值,保证按出队顺序输出结果
3
左孩子入队
左孩子存在就入队,先进先出保证下一层从左开始
4
右孩子入队
右孩子随后入队,排在左孩子之后
5
队列空则停
队列为空说明所有节点都已出队,遍历结束
6第 6 页 · 算法流程:入队、出队、带娃

代码实现

python

用队列把「出队、带娃」翻译成代码,几行就能跑通层次遍历。

代码高亮加载中…

第6行建队列,第10行出队访问,第13、15行「带娃」——左先进右后进,正好保证从左到右的次序。

7第 7 页 · 代码实现

边界细节:空树与队列清空时机

上一页代码能跑通,但真正的坑都在边界:树一开始就是空的怎么办?while 循环为什么写 q.empty()?孩子入队前为什么要判空?这三处写错,程序立刻崩。

空树特判
根为 null 时不入队,直接返回空结果
循环条件
while 以队列非空为条件,队列空即遍历结束
孩子判空
出队节点的左右孩子为 null 时不入队
排队叫号窗口对应 →层次遍历队列

窗口没人排队(队列空)就下班结束,对应循环终止

8第 8 页 · 边界细节:空树与队列清空时机

完整实例逐步走

拿一棵具体的小树,逐轮追踪队列状态与出队访问次序。

1
根 A 入队
队列:[A],树非空,起点入队
2
A 出队访问
访问次序①:A;带娃 B、C 入队,队列:[B, C]
3
B 出队访问
访问次序②:B;带娃 D、E 入队,队列:[C, D, E]
4
C 出队访问
访问次序③:C;C 无孩子,队列:[D, E]
5
D、E 出队
访问次序④⑤:D、E;均为叶子,队列空,结束
9第 9 页 · 完整实例逐步走

自测:写出遍历序列

点击作答

二叉树:根为 1,左孩子 2、右孩子 3;2 的左孩子 4、右孩子 5;3 只有右孩子 6。层次遍历序列是?

10第 10 页 · 自测:写出遍历序列

要点收束

  • ✓按层访问=自上而下、从左到右的次序
  • ✓递归天然走深度,层次次序须靠队列 FIFO 维持
  • ✓核心循环三步:出队访问、孩子按左先右后入队
  • ✓空树直接返回,队列为空才是终止条件
  • ✓序列唯一可验证,是检验实现 correct 的标尺
延伸主题:锯齿形(之字形)层次遍历按层分组输出每层节点右视图:每层最后一个节点
11第 11 页 · 要点收束

课后思考

三个问题,先自己想,再对照参考答案。

1为什么层次遍历必须用队列,换成栈会发生什么?

参考答案从队列先进先出改为栈后进先出,出队顺序颠倒,某一层的右子树会先于左子树被访问,同层从左到右的次序被破坏。想想它退化成了哪种遍历。

2如果要求每一层单独输出成一个数组,该怎么改算法?

参考答案抓住「队列长度=当前层节点数」这个事实:每轮循环先记录 size,只出队 size 个节点,它们恰好是同一层。出队时把孩子入队,正好留给下一层。

3锯齿形(之字形)分层遍历,队列还够用吗?

参考答案队列仍负责分层,但奇偶层输出方向交替即可,多数场景无需换数据结构。若用双端队列在两端出入队,可以进一步实现真正的反向收集,想想两者的区别。

12第 12 页 · 课后思考