|
| 1 | +package heap |
| 2 | + |
| 3 | +import ( |
| 4 | + "container/heap" |
| 5 | +) |
| 6 | + |
| 7 | +// This file is copied from https://go.dev/play/p/350YF5j23xY |
| 8 | +// related to issue https://github.com/golang/go/issues/47632 |
| 9 | +// After the issue is fixed, this file can be removed. |
| 10 | + |
| 11 | +// A Heap is a min-heap backed by a slice. |
| 12 | +type Heap[E any] struct { |
| 13 | + s sliceHeap[E] |
| 14 | +} |
| 15 | + |
| 16 | +// New constructs a new Heap with a comparison function. |
| 17 | +func New[E any](cmp func(E, E) int) *Heap[E] { |
| 18 | + return &Heap[E]{sliceHeap[E]{cmp: cmp}} |
| 19 | +} |
| 20 | + |
| 21 | +// Push pushes an element onto the heap. The complexity is O(log n) |
| 22 | +// where n = h.Len(). |
| 23 | +func (h *Heap[E]) Push(elem E) { |
| 24 | + heap.Push(&h.s, elem) |
| 25 | +} |
| 26 | + |
| 27 | +// Pop removes and returns the minimum element (according to the cmp function) |
| 28 | +// from the heap. Pop panics if the heap is empty. |
| 29 | +// The complexity is O(log n) where n = h.Len(). |
| 30 | +func (h *Heap[E]) Pop() E { |
| 31 | + return heap.Pop(&h.s).(E) |
| 32 | +} |
| 33 | + |
| 34 | +// Peek returns the minimum element (according to the cmp function) in the heap. |
| 35 | +// Peek panics if the heap is empty. |
| 36 | +// The complexity is O(1). |
| 37 | +func (h *Heap[E]) Peek() E { |
| 38 | + return h.s.s[0] |
| 39 | +} |
| 40 | + |
| 41 | +// Len returns the number of elements in the heap. |
| 42 | +func (h *Heap[E]) Len() int { |
| 43 | + return len(h.s.s) |
| 44 | +} |
| 45 | + |
| 46 | +// Empty returns true if the heap is empty. |
| 47 | +func (h *Heap[E]) Empty() bool { |
| 48 | + return len(h.s.s) == 0 |
| 49 | +} |
| 50 | + |
| 51 | +// Slice returns the underlying slice. |
| 52 | +// The slice is in heap order; the minimum value is at index 0. |
| 53 | +// The heap retains the returned slice, so altering the slice may break |
| 54 | +// the invariants and invalidate the heap. |
| 55 | +func (h *Heap[E]) Slice() []E { |
| 56 | + return h.s.s |
| 57 | +} |
| 58 | + |
| 59 | +// SetIndex specifies an optional function to be called |
| 60 | +// when updating the position of any heap element within the slice, |
| 61 | +// including during the element's initial Push. |
| 62 | +// |
| 63 | +// SetIndex must be called at most once, before any calls to Push. |
| 64 | +// |
| 65 | +// When an element is removed from the heap by Pop or Remove, |
| 66 | +// the index function is called with the invalid index -1 |
| 67 | +// to signify that the element is no longer within the slice. |
| 68 | +func (h *Heap[E]) SetIndex(f func(E, int)) { |
| 69 | + h.s.setIndex = f |
| 70 | +} |
| 71 | + |
| 72 | +// Fix re-establishes the heap ordering |
| 73 | +// after the element at index i has changed its value. |
| 74 | +// Changing the value of the element at index i and then calling Fix |
| 75 | +// is equivalent to, but less expensive than, |
| 76 | +// calling h.Remove(i) followed by a Push of the new value. |
| 77 | +// The complexity is O(log n) where n = h.Len(). |
| 78 | +// The index for use with Fix is recorded using the function passed to SetIndex. |
| 79 | +func (h *Heap[E]) Fix(i int) { |
| 80 | + heap.Fix(&h.s, i) |
| 81 | +} |
| 82 | + |
| 83 | +// Remove removes and returns the element at index i from the heap. |
| 84 | +// The complexity is O(log n) where n = h.Len(). |
| 85 | +// The index for use with Remove is recorded using the function passed to SetIndex. |
| 86 | +func (h *Heap[E]) Remove(i int) E { |
| 87 | + return heap.Remove(&h.s, i).(E) |
| 88 | +} |
| 89 | + |
| 90 | +// sliceHeap just exists to use the existing heap.Interface as the |
| 91 | +// implementation of Heap. |
| 92 | +type sliceHeap[E any] struct { |
| 93 | + s []E |
| 94 | + cmp func(E, E) int |
| 95 | + setIndex func(E, int) |
| 96 | +} |
| 97 | + |
| 98 | +func (s *sliceHeap[E]) Len() int { return len(s.s) } |
| 99 | + |
| 100 | +func (s *sliceHeap[E]) Swap(i, j int) { |
| 101 | + s.s[i], s.s[j] = s.s[j], s.s[i] |
| 102 | + if s.setIndex != nil { |
| 103 | + s.setIndex(s.s[i], i) |
| 104 | + s.setIndex(s.s[j], j) |
| 105 | + } |
| 106 | +} |
| 107 | + |
| 108 | +func (s *sliceHeap[E]) Less(i, j int) bool { |
| 109 | + return s.cmp(s.s[i], s.s[j]) < 0 |
| 110 | +} |
| 111 | + |
| 112 | +func (s *sliceHeap[E]) Push(x interface{}) { |
| 113 | + s.s = append(s.s, x.(E)) |
| 114 | + if s.setIndex != nil { |
| 115 | + s.setIndex(s.s[len(s.s)-1], len(s.s)-1) |
| 116 | + } |
| 117 | +} |
| 118 | + |
| 119 | +func (s *sliceHeap[E]) Pop() interface{} { |
| 120 | + e := s.s[len(s.s)-1] |
| 121 | + if s.setIndex != nil { |
| 122 | + s.setIndex(e, -1) |
| 123 | + } |
| 124 | + s.s = s.s[:len(s.s)-1] |
| 125 | + return e |
| 126 | +} |
0 commit comments