Files
leetcode-go/basic/队列实现.md
T

110 lines
2.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
tags: ["Go", "基础数据结构", "队列"]
create time: 2026-05-14 18:00
---
# 队列(Queue)
## 什么时候用
看到 **BFS、层序遍历、滑动窗口** → 用队列。
FIFO:先进去的先出来。类比排队打饭,先到先得。
---
## 模板
```go
type Queue struct {
data []int // 底层用一个 slice 存数据
}
// Push 入队:往末尾追加一个元素
func (q *Queue) Push(v int) {
q.data = append(q.data, v)
}
// Pop 出队:取出第一个元素,再把第一个元素切掉
func (q *Queue) Pop() int {
v := q.data[0] // 先拿到值
q.data = q.data[1:] // 再切除第一个位置
return v
}
// Front 看队首元素但不取走
func (q *Queue) Front() int {
return q.data[0]
}
// Empty 判断是否为空
func (q *Queue) Empty() bool {
return len(q.data) == 0
}
// Len 当前有多少个元素
func (q *Queue) Len() int {
return len(q.data)
}
```
**核心思路就两件事:** `append` 往尾巴加,`data[1:]` 从头部踢。简单粗暴有效。
---
## BFS 用法
BFS 的精髓就是:**把当前层的节点全部取出,然后把它们的子节点全部放进队列等下一轮处理。**
```go
q := &Queue{}
q.Push(root) // 先把根节点放进去
for !q.Empty() { // 队列不空就一直处理
node := q.Front() // 看队首
q.Pop() // 弹出队首
if node.Left != nil {
q.Push(node.Left) // 左子节点入队
}
if node.Right != nil {
q.Push(node.Right) // 右子节点入队
}
}
```
如果要**按层**输出(比如 LeetCode 102),在外层循环里记一下当前层有几个节点,内层只处理这么多:
```go
for !q.Empty() {
size := q.Len() // 当前层有几个节点
level := []int{} // 存这一层的结果
for i := 0; i < size; i++ {
node, _ := q.Pop()
level = append(level, node.Val)
if node.Left != nil {
q.Push(node.Left)
}
if node.Right != nil {
q.Push(node.Right)
}
}
result = append(result, level) // 这一层处理完了,存起来
}
```
> [!tip] 🔑 关键点
>
> `size := q.Len()` 这行必须在内层循环前执行。因为内层会不断 Push 新节点进入队列,如果不提前记录当前层的大小,就会无限循环下去。
---
## 对应题目
| 难度 | 题目 | 要点 |
|------|------|------|
| ⭐⭐ | [[102.binary-tree-level-order-traversal]] | 层序遍历标准写法 |
| ⭐⭐ | [[127.word-ladder]] | BFS 求最短路径 |
| ⭐⭐⭐ | [[239.sliding-window-maximum]] | 单调队列(进阶) |