美文网首页
Go 语言中如何使用堆 Heap

Go 语言中如何使用堆 Heap

作者: 专职跑龙套 | 来源:发表于2021-05-06 06:26 被阅读0次

    Go 提供了 container/heap 这个包来实现堆的操作。堆实际上是一个树的结构,每个元素的值都是它的子树中最小的,因此根节点 index = 0 的值是最小的,即最小堆。

    堆也是实现优先队列 Priority Queue 的常用方式。

    堆中元素的类型需要实现 heap.Interface 这个接口:

    type Interface interface {
        sort.Interface
        Push(x interface{}) // add x as element Len()
        Pop() interface{}   // remove and return element Len() - 1.
    }
    

    其中 sort.Interface 包括 Len(), Less, Swap 方法:

    一个完整的示例如下:
    注意注释中的一句话 Push 和 Pop 方法需要使用指针,因为它们会修改 slice 的长度,而不仅仅只内容

    import (
        "container/heap"
        "fmt"
    )
    
    // An IntHeap is a min-heap of ints.
    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{}) {
        // Push and Pop use pointer receivers because they modify the slice's length,
        // not just its contents.
        *h = append(*h, x.(int))
    }
    
    func (h *IntHeap) Pop() interface{} {
        old := *h
        n := len(old)
        x := old[n-1]
        *h = old[0 : n-1]
        return x
    }
    
    // This example inserts several ints into an IntHeap, checks the minimum,
    // and removes them in order of priority.
    func main() {
        h := &IntHeap{2, 1, 5}
        heap.Init(h)
        heap.Push(h, 3)
        fmt.Printf("minimum: %d\n", (*h)[0]) // minimum: 1
        for h.Len() > 0 {
            fmt.Printf("%d ", heap.Pop(h)) // 1 2 3 5
        }
    }
    

    Leetcode 692. Top K Frequent Words 也可以使用 Go 语言通过构造 PriorityQueue 来实现:

    type Item struct {
        word  string
        count int
    }
    
    type ItemHeap []Item
    
    func (h ItemHeap) Len() int { return len(h) }
    
    func (h ItemHeap) Less(i, j int) bool {
        if h[i].count != h[j].count {
            return h[i].count < h[j].count
        } else {
            return h[i].word > h[j].word
        }
    }
    
    func (h ItemHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
    
    func (h *ItemHeap) Push(val interface{}) {
        *h = append(*h, val.(Item))
    }
    
    func (h *ItemHeap) Pop() interface{} {
        old := *h
        n := len(old)
        x := old[n-1]
        *h = old[0 : n-1]
        return x
    }
    
    func topKFrequent(words []string, k int) []string {
        countMap := make(map[string]int)
        for _, word := range words {
            countMap[word]++
        }
    
        h := &ItemHeap{}
        for w, v := range countMap {
            heap.Push(h, Item{
                word:  w,
                count: v,
            })
    
            if h.Len() > k {
                heap.Pop(h)
            }
        }
    
        res := make([]string, h.Len())
        for i := h.Len() - 1; i >= 0; i-- {
            item := heap.Pop(h).(Item)
            res[i] = item.word
        }
        return res
    }
    

    相关文章

      网友评论

          本文标题:Go 语言中如何使用堆 Heap

          本文链接:https://www.haomeiwen.com/subject/xmdrdltx.html