

新闻资讯
技术学院Go标准库container/heap不提供现成堆类型,而是通过实现heap.Interface接口(含Len、Less、Swap、Push、Pop五方法)配合heap.Init/Push/Pop函数使用;需传指针、必调Init、Pop非取顶、无并发安全。
Go 语言标准库 container/heap 并不直接提供一个“堆类型”,而是定义了一套接口和通用操作函数,要求你自行实现 heap.Interface(本质是 sort.Interface 的扩展),再配合 heap.Init、heap.Push、heap.Pop 等函数使用。核心在于:**你提供底层切片 + 满足堆序的比较逻辑,heap 包负责维护堆结构。**
要让自定义类型支持堆操作,必须实现以下五个方法:
a[i] 时返回 true)
常见错误:忘记在 Push 中用 *h = append(*h, x.(YourType)),或在 Pop 中写成 res := (*h)[len(*h)-1]; *h = (*h)[:len(*h)-1]; return res —— 顺序不能反,否则切片截取会出错。
以整数最小堆为例,支持入队、出队、查看队首:
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)
item := old[n-1]
*h = old[0 : n-1]
return item
}
// 使用示例
func main() {
h := &IntHeap{}
heap.Init(h)
heap.Push(h, 3)
heap.Push(h, 1)
heap.Push(h, 4)
fmt.Println(heap.Pop(h)) // 1
fmt.Println(heap.Pop(h)) // 3
fmt.Println(heap.Pop(h)) // 4
}
只需修改 Less 方法即可切换行为:
Less(i,j) 改为 return h[i] > h[j]
type Task struct {
Name string
Priority int
}
type TaskHeap []Task
func (h TaskHeap) Less(i, j int) bool { return h[i].Priority < h[j].Priority } // 优先级小的先执行
切片必须是指针传入:所有 heap.Xxx 函数都接收 interface{},实际期望的是指向实现了 heap.Interface 的变量的指针(如 &IntHeap{}),否则修改不会反映到原切片。
初始化不可省略:即使切片已有序或为空,首次使用前也必须调用 heap.Init(h),它会按堆序重排底层切片。
Pop 不等于取顶:heap.Pop 是删除并返回堆顶,若只想看顶元素,用 h[0](前提是 h.Len() > 0)。
线程不安全:标准 heap 包无并发保护,多 goroutine 访问需自行加锁。