Go中的堆结构+大根堆小根堆的接口实现方法
1.Heap接口说明
在Go中,堆结构的实现依赖于使用者对于Heap接口进行实现,更加灵活,但也需要额外的工作量。
import (
"container/heap"
)
在Heap.go中定义了接口如下:
type Interface interface {
sort.Interface
Push(x interface{}) // add x as element Len()
Pop() interface{} // remove and return element Len() - 1.
}
可以发现,要实现这个接口需要我们实现2个方法和一个sort接口,我们首先来看这两个方法。
2.Push和Pop方法实现
我们首先来对Heap中的两个方法Push和Pop进行实现:
Push的官方注释add x as element Len()只是让我们把数字放在heap的末尾。
手动实现:
func (h *IntHeap) Push(x interface{}) {
// Push and Pop use pointer receivers because they modify the slice's length,
// not just its contents.
*h = append(*h, x.(int))
}
但是使用过程中,调用Push操作时,会先调用Heap.go中的Push(h Interface,x interface{})
// Push pushes the element x onto the heap.
// The complexity is O(log n) where n = h.Len().
func Push(h Interface, x interface{}) {
h.Push(x)
up(h, h.Len()-1)
}
由这个函数再调用我们实现的Push(x interface{})将数放入heap末尾,使用原生写好的up函数将其向上放置合适的位置。
func up(h Interface, j int) {
for {
i := (j - 1) / 2 // parent
if i == j || !h.Less(j, i) {
break
}
h.Swap(i, j)
j = i
}
}
Pop函数官方注释remove and return element Len() - 1.需要我们移出一个元素并将数组长度-1,也就是说将数组的末元素移出。
手动实现:
func (h *IntHeap) Pop() interface{} {
old := *h
n := len(old)
x := old[n-1]
*h = old[0 : n-1]
return x
}
我们只是移出了末尾元素,如何保证末尾元素就是最大/最小值呢?
和Push一样,Pop也会首先调用官方的Heap.go里的函数,Pop(h Interface) interface{}
// Pop removes and returns the minimum element (according to Less) from the heap.
// The complexity is O(log n) where n = h.Len().
// Pop is equivalent to Remove(h, 0).
func Pop(h Interface) interface{} {
n := h.Len() - 1
h.Swap(0, n)
down(h, 0, n)
return h.Pop()
}
可以看到,就如同手动删除大小根堆的元素一样,我们会将堆的首末元素呼唤,然后将末元素在首位置使用down函数向下调整至合适的位置然后再删除末尾的原首元素,其中的down函数也是原生实现好的。
func down(h Interface, i0, n int) bool {
i := i0
for {
j1 := 2*i + 1
if j1 >= n || j1 < 0 { // j1 < 0 after int overflow
break
}
j := j1 // left child
if j2 := j1 + 1; j2 < n && h.Less(j2, j1) {
j = j2 // = 2*i + 2 // right child
}
if !h.Less(j, i) {
break
}
h.Swap(i, j)
i = j
}
return i > i0
}
3.sort接口实现
上文提到我们还要实现sort接口。
// Package sort provides primitives for sorting slices and user-defined
// collections.
package sort
// A type, typically a collection, that satisfies sort.Interface can be
// sorted by the routines in this package. The methods require that the
// elements of the collection be enumerated by an integer index.
type Interface interface {
// Len is the number of elements in the collection.
Len() int
// Less reports whether the element with
// index i should sort before the element with index j.
Less(i, j int) bool
// Swap swaps the elements with indexes i and j.
Swap(i, j int)
}
我们还需要对sort中的三个方法进行实现。
func (h IntHeap) Len() int { return len(h) }
// Less 为了实现大根堆,Less在大于时返回小于
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] }
至此我们就实现了一个大根堆的构建,小根堆只需要改动sort方法即可。
使用中,需要对堆进行初始化:
type IntHeap []int
同时,对堆进行大根堆的初始化
func Init(h Interface) {
// heapify
n := h.Len()
for i := n/2 - 1; i >= 0; i-- {
down(h, i, n)
}
}

浙公网安备 33010602011771号