一句话总结:
二叉树的层序遍历就像剥洋葱——一层一层剥开,每层从左到右处理节点,用队列来维护“待处理队伍”!
一、层序遍历原理
核心思想: 使用队列(FIFO)依次处理每一层节点:
-
根节点入队
-
循环处理队列中的节点,每次处理一层:
- 记录当前层的节点数量
- 依次出队节点,将其子节点入队
-
收集每层的节点值
二、Kotlin 代码实现
// 定义二叉树节点
class TreeNode(var value: Int) {
var left: TreeNode? = null
var right: TreeNode? = null
}
fun levelOrder(root: TreeNode?): List<List<Int>> {
val result = mutableListOf<List<Int>>()
if (root == null) return result
val queue = ArrayDeque<TreeNode>()
queue.add(root) // 根节点入队
while (queue.isNotEmpty()) {
val levelSize = queue.size // 当前层的节点数
val currentLevel = mutableListOf<Int>()
repeat(levelSize) { // 处理当前层所有节点
val node = queue.removeFirst()
currentLevel.add(node.value)
// 子节点入队(下一层)
node.left?.let { queue.add(it) }
node.right?.let { queue.add(it) }
}
result.add(currentLevel)
}
return result
}
三、测试用例
fun main() {
// 测试用例1:普通二叉树
// 3
// / \
// 9 20
// / \
// 15 7
val root1 = TreeNode(3).apply {
left = TreeNode(9)
right = TreeNode(20).apply {
left = TreeNode(15)
right = TreeNode(7)
}
}
println(levelOrder(root1)) // 输出 [[3], [9,20], [15,7]]
// 测试用例2:空树
println(levelOrder(null)) // 输出 []
// 测试用例3:单节点树
val root3 = TreeNode(1)
println(levelOrder(root3)) // 输出 [[1]]
// 测试用例4:只有左子树
// 1
// /
// 2
// /
// 3
val root4 = TreeNode(1).apply {
left = TreeNode(2).apply {
left = TreeNode(3)
}
}
println(levelOrder(root4)) // 输出 [[1], [2], [3]]
}
四、复杂度分析
| 操作 | 时间复杂度 | 空间复杂度 | 说明 |
|---|---|---|---|
| 层序遍历 | O(n) | O(n) | n为节点数,队列最大存储最后一层节点(约n/2) |
五、分步图解(以测试用例1为例)
初始队列:[3]
第1层处理:
取出3 → 收集[3]
子节点9、20入队 → 队列[9,20]
结果:[[3]]
第2层处理:
队列大小=2 → 处理两次
取出9 → 收集[9],无子节点
取出20 → 收集[20],子节点15、7入队 → 队列[15,7]
结果:[[3], [9,20]]
第3层处理:
队列大小=2 → 处理两次
取出15 → 收集[15],无子节点
取出7 → 收集[7],无子节点
结果:[[3], [9,20], [15,7]]
六、应用场景
- 按层级打印树结构
- 寻找每层最大值/平均值(如LeetCode 102、637题)
- 判断完全二叉树(层序遍历中不应出现空节点后还有非空节点)
口诀:
层序遍历用队列,
一层一波按顺序。
左子右子依次进,
剥完洋葱就收工!