排序与集合
包总览
| 包 | 核心类型/函数 | 用途 |
|---|
sort | Sort, Search, Slice | 排序与搜索 |
slices | Sort, Contains, BinarySearch(Go 1.21+) | 泛型 slice 操作 |
maps | Keys, Values, Clone, Copy(Go 1.21+) | 泛型 map 操作 |
container/list | List, Element | 双向链表 |
container/heap | Heap, Interface | 优先队列 |
container/ring | Ring | 环形缓冲 |
sort 包
基本排序
import "sort"
// 基本类型排序
sort.Ints([]int{3, 1, 4, 1, 5, 9, 2, 6}) // [1 1 2 3 4 5 6 9]
sort.Float64s([]float64{3.14, 1.41, 2.71})
sort.Strings([]string{"banana", "apple", "cherry"})
// 检查是否已排序
sort.IntsAreSorted([]int{1, 2, 3}) // true
sort.StringsAreSorted([]string{"a", "b"}) // true
// 搜索(已排序的 slice)
idx := sort.SearchInts([]int{1, 3, 5, 7, 9}, 5) // 2
idx := sort.SearchStrings([]string{"a", "b", "c"}, "b") // 1
自定义排序
// 方式1:实现 sort.Interface
type ByAge []User
func (a ByAge) Len() int { return len(a) }
func (a ByAge) Less(i, j int) bool { return a[i].Age < a[j].Age }
func (a ByAge) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
users := []User{{Name: "小徐", Age: 28}, {Name: "小王", Age: 25}}
sort.Sort(ByAge(users)) // 按年龄升序
// 方式2:sort.Slice(更简洁)
sort.Slice(users, func(i, j int) bool {
return users[i].Age < users[j].Age
})
// 降序
sort.Slice(users, func(i, j int) bool {
return users[i].Age > users[j].Age
})
// 多字段排序
sort.Slice(users, func(i, j int) bool {
if users[i].Age != users[j].Age {
return users[i].Age < users[j].Age // 先按年龄
}
return users[i].Name < users[j].Name // 年龄相同按名字
})
// 稳定排序(相等元素保持原顺序)
sort.SliceStable(users, func(i, j int) bool {
return users[i].Age < users[j].Age
})
sort.SliceStable vs sort.Slice
| 函数 | 稳定性 | 时间复杂度 | 适用 |
|---|
| sort.Slice | 不稳定 | O(n log n) | 通用 |
| sort.SliceStable | 稳定 | O(n log² n) | 需要保持相等元素顺序 |
sort.Search(二分搜索)
// 在已排序的 slice 中搜索(返回第一个满足条件的位置)
nums := []int{1, 3, 5, 7, 9, 11, 13}
idx := sort.Search(len(nums), func(i int) bool {
return nums[i] >= 7
})
// idx = 3, nums[3] = 7
// 查找第一个 >= 6 的元素
idx := sort.Search(len(nums), func(i int) bool {
return nums[i] >= 6
})
// idx = 3, nums[3] = 7(6 不存在,返回插入位置)
// 自定义搜索
type User struct {
ID int
Name string
}
users := []User{{1, "A"}, {3, "B"}, {5, "C"}, {7, "D"}}
idx := sort.Search(len(users), func(i int) bool {
return users[i].ID >= 5
})
// idx = 2, users[2] = {5, "C"}
slices 包(Go 1.21+)
import "slices"
// 排序
s := []int{3, 1, 4, 1, 5, 9, 2, 6}
slices.Sort(s) // [1 1 2 3 4 5 6 9]
slices.SortFunc(s, func(a, b int) int { return b - a }) // 降序
// 字符串排序
strs := []string{"banana", "apple", "cherry"}
slices.Sort(strs) // [apple banana cherry]
// 搜索
slices.Contains(s, 5) // true
slices.Index(s, 4) // 3
slices.BinarySearch(s, 5) // (4, true)
// 比较
slices.Equal([]int{1,2,3}, []int{1,2,3}) // true
slices.Compare([]int{1,2}, []int{1,3}) // -1
// 操作
slices.Reverse(s) // 原地反转
slices.Delete(s, 1, 3) // 删除 [1,3) 范围
slices.Insert(s, 1, 99) // 在索引1插入
// 最值
slices.Max(s) // 9
slices.Min(s) // 1
slices.MaxFunc(users, func(a, b User) int {
return a.Age - b.Age
})
// 去重(需先排序)
slices.Sort(s)
slices.Compact(s) // 去除连续重复元素
sort.SortFunc 比较函数
// Go 1.21+ 的比较函数签名:func(a, b T) int
// 返回负数: a < b
// 返回 0: a == b
// 返回正数: a > b
slices.SortFunc(users, func(a, b User) int {
return cmp.Compare(a.Age, b.Age) // 使用 cmp.Compare
})
maps 包(Go 1.21+)
import "maps"
m := map[string]int{"a": 1, "b": 2, "c": 3}
// 获取所有 key(顺序随机)
keys := maps.Keys(m) // []string{"a", "b", "c"}
// 获取所有 value
values := maps.Values(m) // []int{1, 2, 3}
// 克隆
m2 := maps.Clone(m)
// 复制
maps.Copy(m, map[string]int{"d": 4, "e": 5})
// 删除满足条件的
maps.DeleteFunc(m, func(k string, v int) bool {
return v < 2
})
// 比较
maps.Equal(m, m2) // true
container/list(双向链表)
import "container/list"
l := list.New()
// 添加
l.PushBack("tail") // 尾部添加
l.PushFront("head") // 头部添加
l.PushBackList(other) // 尾部追加另一个链表
// 遍历
for e := l.Front(); e != nil; e = e.Next() {
fmt.Println(e.Value)
}
// 从尾部遍历
for e := l.Back(); e != nil; e = e.Prev() {
fmt.Println(e.Value)
}
// 删除
e := l.Front()
l.Remove(e)
// 在指定元素前/后插入
l.InsertBefore("new", e)
l.InsertAfter("new", e)
// 获取
l.Len() // 长度
l.Front() // 头元素
l.Back() // 尾元素
// 移动
l.MoveToFront(e)
l.MoveToBack(e)
l.MoveBefore(e, target)
l.MoveAfter(e, target)
container/heap(优先队列)
import "container/heap"
// 实现 heap.Interface
type IntHeap []int
func (h IntHeap) Len() int { return len(h) }
func (h IntHeap) Less(i, j int) bool { return h[i] < h[j] } // 小顶堆
func (h IntHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *IntHeap) Push(x interface{}) {
*h = append(*h, x.(int))
}
func (h *IntHeap) Pop() interface{} {
old := *h
n := len(old)
x := old[n-1]
*h = old[:n-1]
return x
}
// 使用
h := &IntHeap{3, 1, 4, 1, 5, 9, 2, 6}
heap.Init(h) // 初始化堆
heap.Push(h, 0) // 插入元素
min := heap.Pop(h) // 弹出最小元素(0)
// 大顶堆:修改 Less 函数
func (h IntHeap) Less(i, j int) bool { return h[i] > h[j] }
优先队列应用
// 任务优先级队列
type Task struct {
Priority int
Name string
}
type PriorityQueue []Task
func (pq PriorityQueue) Len() int { return len(pq) }
func (pq PriorityQueue) Less(i, j int) bool {
return pq[i].Priority > pq[j].Priority // 大顶堆:优先级高的先出
}
func (pq PriorityQueue) Swap(i, j int) { pq[i], pq[j] = pq[j], pq[i] }
func (pq *PriorityQueue) Push(x interface{}) { *pq = append(*pq, x.(Task)) }
func (pq *PriorityQueue) Pop() interface{} {
old := *pq
n := len(old)
x := old[n-1]
*pq = old[:n-1]
return x
}
// 使用
pq := &PriorityQueue{}
heap.Init(pq)
heap.Push(pq, Task{Priority: 3, Name: "high"})
heap.Push(pq, Task{Priority: 1, Name: "low"})
heap.Push(pq, Task{Priority: 2, Name: "medium"})
for pq.Len() > 0 {
task := heap.Pop(pq).(Task)
fmt.Println(task.Name) // high, medium, low
}
container/ring(环形缓冲)
import "container/ring"
// 创建大小为 3 的环
r := ring.New(3)
// 填充数据
for i := 0; i < 3; i++ {
r.Value = i
r = r.Next()
}
// 遍历
r.Do(func(v interface{}) {
fmt.Println(v) // 0, 1, 2
})
// 长度
n := r.Len() // 3
// 移动
r = r.Move(2) // 向前移动 2 步
// 链接两个环
r.Link(otherRing)
数据结构选型指南
| 需求 | 推荐类型 | 时间复杂度 |
|---|
| 有序数组 | []T + sort | 排序 O(n log n), 搜索 O(log n) |
| 动态数组 | []T | 追加 O(1) amortized, 访问 O(1) |
| 键值查找 | map[K]V | O(1) 平均 |
| 去重 | map[K]struct{} | O(1) |
| 有序键值 | 无内置 | 用 sorted slice 或第三方库 |
| 优先队列 | container/heap | 插入/删除 O(log n) |
| 双向链表 | container/list | 头尾操作 O(1) |
| 队列 (FIFO) | []T 或 list.List | O(1) |
| 栈 (LIFO) | []T | O(1) |
| 环形缓冲 | container/ring | O(1) |