目录
前言
在平时刷 LeetCode 准备算法题的时候不可避免的会遇到利用大(小)根堆或优先队列(利用堆实现)实现的解法。在其他语言中或许有现成的优先队列数据结构(例如 C++ 中的 priority_queue)因此实现比较方便,但是在 Golang 中并没有现成的数据结构可以使用,需要利用 heap 包去实现堆。
在看题解或其他人的 Golang 代码时,经常发现不同的实现方式,例如下面这种。
func smallestK(arr []int, k int) []int {
if k == 0 {
return nil
}
h := &hp{arr[:k]}
heap.Init(h)
...
}
type hp struct{ sort.IntSlice }
func (h hp) Less(i, j int) bool { return h.IntSlice[i] > h.IntSlice[j] }
func (hp) Push(interface{}) {}
func (hp) Pop() (_ interface{}) { return }
对于 heap 包不是很了解的话可能会很奇怪,Push 方法和 Pop 方法里面好像没有任何逻辑?难道只需要用这种抽象的方法去表示我的 hp 结构体实现了 Push 方法和 Pop 方法就可以实现一个堆了么(本菜鸡之前真的是这么理解的...)。
然而事实的真相并没有那么简单,提前剧透一下这么写的原因其实是因为在这道题目中并不需要使用到 Push 和 Pop 的代码逻辑所以实现时干脆不写逻辑了。一下子无法理解这个原因的话可以看完文章后回看理解。
heap 包源码解析
heap.Interface
使用 heap 包构建一个堆第一步就是调用 heap.Init 函数,该函数长下面这样。
func Init(h Interface) {
// heapify
n := h.Len()
for i := n/2 - 1; i >= 0; i-- {
down(h, i, n)
}
}
函数内部的代码逻辑其实不重要&