--- 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]] | 单调队列(进阶) |