为什么heap.Pop与反向数组一起使用?

时间:2019-10-11 15:29:30

标签: arrays go heap

我正在使用Package Heap中的IntHeap示例。对于minHEAP来说,每件事看起来都很简单。看一下如何获得最小值:我们只需要(*h)[0]值。就像在堆说明中一样,根节点返回最小值

fmt.Printf("minimum: %d\n", (*h)[0]) // It will returns 1

奇怪的事情始于Pop()方法。在这种情况下,最小值存储在数组的末尾。 x := old[n-1]。但是上面的2行我从索引0得到了相同的最小值。

嗯...这很有趣。 Go代表Pop方法的反向数组如何发生? 想象以不同的方法排列数组的不同顺序是很奇怪的,而且是微小的,不常见的。

我在示例中添加了两行,是的,将反向数组传递给Pop方法:

fmt.Println("In Pop",*h) // In Pop [2 3 5 1]
fmt.Println("In Main",*h) // In Main [1 2 5 3]
  • 为什么每次都需要反转数组?
  • 每次Pop通话都需要O(n)吗?

这是一个完整的示例,其中有两个更改:

// This example demonstrates an integer heap built using the heap interface.
package main

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{} {
    fmt.Println("In Pop",*h) // In Pop [2 3 5 1]
    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])
    fmt.Println("In Main",*h) // In Main [1 2 5 3]
    for h.Len() > 0 {
        fmt.Printf("%d ", heap.Pop(h))
    }
}

和输出

minimum: 1
In Main [1 2 5 3]
In Pop [2 3 5 1]
1 In Pop [3 5 2]
2 In Pop [5 3]
3 In Pop [5]
5 

2 个答案:

答案 0 :(得分:2)

使用Init从切片初始化堆时,它将通过重新排列切片来建立堆不变式。此操作为O(n),在初始化时仅发生一次,而不是在每次弹出时都发生!

然后,当您Pop时,每个Pop只需要O(log n)。执行初始化对于确保我们可以弹出O(log n)至关重要。

详细了解堆on Wikipediaarticle on Heapsort具有 heapify 操作的伪代码,该操作由heap.Init

执行

Pop的作用不可逆转。它:

  1. 将最小元素(位于[0]处)与基础切片中的最后一个元素交换。现在最小元素在最后,元素[0]在堆中的“错误”位置。
  2. 使用down原语将新元素[0]移动到堆中的正确位置。这会重新整理堆中的某些元素-但这不是还原。
  3. 删除并返回元素[n-1],该元素从步骤1开始就是原始的最小元素。

答案 1 :(得分:-1)

这是不可逆的。这是一种从MinHeap中删除最小元素的算法。

  1. 将根元素与最后一个元素交换。
  2. 删除最少的元素
  3. 堆砌结构。

在当前情况下,程序包委派给开发人员步骤2。然后对除最后一个元素以外的所有堆执行步骤1和步骤3。

https://youtu.be/WCm3TqScBM8?t=391