From b1a29548d27573cd1b8f34f02087042c0d5a1978 Mon Sep 17 00:00:00 2001 From: wonder Date: Wed, 26 Aug 2026 06:21:01 +0000 Subject: [PATCH] =?UTF-8?q?add:=20=E9=98=9F=E5=88=97=E7=AE=97=E6=B3=95?= =?UTF-8?q?=E7=AC=94=E8=AE=B0=EF=BC=88Go=20=E8=AF=AD=E8=A8=80=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/queue.md | 288 ++++++++++++++++++++++++++++++++++++++++ mkdocs.yml | 1 + 2 files changed, 289 insertions(+) create mode 100644 docs/algorithm/queue.md diff --git a/docs/algorithm/queue.md b/docs/algorithm/queue.md new file mode 100644 index 0000000..1d3d475 --- /dev/null +++ b/docs/algorithm/queue.md @@ -0,0 +1,288 @@ +# 队列 + +!!! note "💡 一句话概述" + 队列是一种先进先出(FIFO)的数据结构,只允许从一端入队、另一端出队。 + +--- + +## 🔑 核心概念 + +1. **FIFO 原则**:先入队的元素先出队,类似于排队买票 +2. **操作**:入队(Enqueue)从队尾添加,出队(Dequeue)从队头移除 +3. **类型**:顺序队列、链式队列、循环队列、双端队列 + +--- + +## 📝 详细说明 + +队列是一种受限的线性表,限制只在表的两端进行操作: + +- **队头(Front)**:允许出队的一端 +- **队尾(Rear)**:允许入队的一端 + +**适用场景**:任务调度、消息队列、BFS 遍历、缓冲区、打印队列等。 + +--- + +## 💻 代码示例 + +### 顺序队列(数组实现) + +```go +package main + +import "fmt" + +type Queue struct { + data []int + head int + tail int + size int +} + +func NewQueue(capacity int) *Queue { + return &Queue{ + data: make([]int, capacity), + head: 0, + tail: 0, + size: capacity, + } +} + +func (q *Queue) Enqueue(val int) bool { + if q.tail == q.size { + return false // 队满 + } + q.data[q.tail] = val + q.tail++ + return true +} + +func (q *Queue) Dequeue() (int, bool) { + if q.head == q.tail { + return 0, false // 队空 + } + val := q.data[q.head] + q.head++ + return val, true +} + +func (q *Queue) IsEmpty() bool { + return q.head == q.tail +} + +func main() { + q := NewQueue(5) + q.Enqueue(1) + q.Enqueue(2) + q.Enqueue(3) + + for !q.IsEmpty() { + val, _ := q.Dequeue() + fmt.Println(val) // 输出: 1 2 3 + } +} +``` + +### 链式队列(链表实现) + +```go +package main + +import "fmt" + +type Node struct { + Val int + Next *Node +} + +type LinkedQueue struct { + head *Node + tail *Node + size int +} + +func NewLinkedQueue() *LinkedQueue { + return &LinkedQueue{} +} + +func (q *LinkedQueue) Enqueue(val int) { + node := &Node{Val: val} + if q.tail != nil { + q.tail.Next = node + } + q.tail = node + if q.head == nil { + q.head = node + } + q.size++ +} + +func (q *LinkedQueue) Dequeue() (int, bool) { + if q.head == nil { + return 0, false + } + val := q.head.Val + q.head = q.head.Next + if q.head == nil { + q.tail = nil + } + q.size-- + return val, true +} + +func main() { + q := NewLinkedQueue() + q.Enqueue(10) + q.Enqueue(20) + + for { + val, ok := q.Dequeue() + if !ok { + break + } + fmt.Println(val) // 输出: 10 20 + } +} +``` + +### 循环队列 + +```go +package main + +import "fmt" + +type CircularQueue struct { + data []int + head int + tail int + size int + cap int +} + +func NewCircularQueue(capacity int) *CircularQueue { + return &CircularQueue{ + data: make([]int, capacity), + head: 0, + tail: 0, + size: 0, + cap: capacity, + } +} + +func (q *CircularQueue) Enqueue(val int) bool { + if q.size == q.cap { + return false + } + q.data[q.tail] = val + q.tail = (q.tail + 1) % q.cap + q.size++ + return true +} + +func (q *CircularQueue) Dequeue() (int, bool) { + if q.size == 0 { + return 0, false + } + val := q.data[q.head] + q.head = (q.head + 1) % q.cap + q.size-- + return val, true +} + +func main() { + q := NewCircularQueue(3) + q.Enqueue(1) + q.Enqueue(2) + q.Enqueue(3) + + val, _ := q.Dequeue() // 出队 1 + fmt.Println("出队:", val) + + q.Enqueue(4) // 入队 4 + + for !q.IsEmpty() { + val, _ := q.Dequeue() + fmt.Println(val) // 输出: 2 3 4 + } +} +``` + +--- + +## ⚠️ 常见陷阱 + +!!! warning "顺序队列的假溢出" + 用数组实现队列时,即使前面有空位,tail 到达数组末尾也无法入队。解决办法:使用循环队列,通过取模运算让队列"首尾相接"。 + +!!! warning "队空和队满的判断条件" + 循环队列中,`head == tail` 表示队空,`(tail + 1) % cap == head` 表示队满(牺牲一个位置)。或者额外维护一个 `size` 变量来区分。 + +--- + +## 🏋️ 练习题 + +??? question "练习 1:用两个栈实现队列" + 使用两个栈实现队列的 push 和 pop 操作。 + + ```go + type MyQueue struct { + inStack []int + outStack []int + } + + func (q *MyQueue) Push(x int) { + q.inStack = append(q.inStack, x) + } + + func (q *MyQueue) Pop() int { + if len(q.outStack) == 0 { + for len(q.inStack) > 0 { + q.outStack = append(q.outStack, q.inStack[len(q.inStack)-1]) + q.inStack = q.inStack[:len(q.inStack)-1] + } + } + val := q.outStack[len(q.outStack)-1] + q.outStack = q.outStack[:len(q.outStack)-1] + return val + } + ``` + +??? question "练习 2:用队列实现 BFS" + 用队列实现二叉树的层序遍历。 + + ??? success "答案" + ```go + func levelOrder(root *TreeNode) [][]int { + if root == nil { + return nil + } + result := [][]int{} + queue := []*TreeNode{root} + + for len(queue) > 0 { + level := []int{} + size := len(queue) + for i := 0; i < size; i++ { + node := queue[0] + queue = queue[1:] + level = append(level, node.Val) + if node.Left != nil { + queue = append(queue, node.Left) + } + if node.Right != nil { + queue = append(queue, node.Right) + } + } + result = append(result, level) + } + return result + } + ``` + +--- + +## 🔗 相关链接 + +- [Go container/list](https://pkg.go.dev/container/list) — 标准库双向链表,可用于实现队列 diff --git a/mkdocs.yml b/mkdocs.yml index ae8083d..37cf9e9 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -101,3 +101,4 @@ nav: - 布谷鸟过滤器: algorithm/cuckoo-filter.md - HeavyKeeper: algorithm/heavykeeper.md - 二叉树的遍历: algorithm/binary-tree-traversal.md + - 队列: algorithm/queue.md