Documentation
¶
Overview ¶
Package heap provides a min-heap data structure.
Example (Changed) ¶
package main
import (
"fmt"
"github.com/jba/heap"
)
func main() {
type intWithIndex struct {
value int
index int
}
h := heap.NewIndexed(func(a, b *intWithIndex) int {
return a.value - b.value
}, func(v *intWithIndex, i int) { v.index = i })
item1 := &intWithIndex{value: 5}
item2 := &intWithIndex{value: 3}
item3 := &intWithIndex{value: 7}
h.Init([]*intWithIndex{item1, item2, item3})
// Get the current min.
fmt.Println(h.Min().value)
// Modify item1's value (currently 5, make it smaller).
item1.value = 1
// Call Changed to restore heap invariant.
h.Changed(item1.index)
// Now item1 should be the new minimum.
fmt.Println(h.Min().value)
}
Output: 3 1
Example (Delete) ¶
package main
import (
"fmt"
"github.com/jba/heap"
)
func main() {
type intWithIndex struct {
value int
index int
}
h := heap.NewIndexed(func(a, b *intWithIndex) int {
return a.value - b.value
}, func(v *intWithIndex, i int) { v.index = i })
item1 := &intWithIndex{value: 5}
item2 := &intWithIndex{value: 3}
item3 := &intWithIndex{value: 7}
item4 := &intWithIndex{value: 1}
h.Init([]*intWithIndex{item1, item2, item3, item4})
// Delete specific items by their index.
h.Delete(item1.index)
h.Delete(item2.index)
// Remaining elements.
for v := range h.Drain() {
fmt.Println(v.value)
}
}
Output: 1 7
Example (Heapsort) ¶
package main
import (
"cmp"
"fmt"
"github.com/jba/heap"
)
func main() {
// To implement heapsort, first build a heap, then drain it.
h := heap.New(cmp.Compare[int])
h.Init([]int{7, 2, 9, 1, 5})
for v := range h.Drain() {
fmt.Println(v)
}
}
Output: 1 2 5 7 9
Example (MaxHeap) ¶
package main
import (
"fmt"
"github.com/jba/heap"
)
func main() {
// Create a max-heap using a custom comparison function.
h := heap.New(func(a, b int) int {
// Reverse the comparison for max-heap.
return b - a
})
h.Init([]int{5, 3, 7, 1})
// Extract maximum values.
fmt.Println(h.TakeMin()) // "Min" extracts the element that compares smallest
fmt.Println(h.TakeMin())
}
Output: 7 5
Example (PriorityQueue) ¶
This example creates a priority queue with some items, adds and manipulates an item, and then removes the items in priority order.
// This example demonstrates a priority queue built using the heap package.
package main
import (
"cmp"
"fmt"
"github.com/jba/heap"
)
// An Item is something we manage in a priority queue.
type Item struct {
value string // The value of the item; arbitrary.
priority int // The priority of the item in the queue.
// The index is needed by update and is maintained by the heap.
index int // The index of the item in the heap.
}
// This example creates a priority queue with some items, adds and manipulates an item,
// and then removes the items in priority order.
func main() {
// Create a priority queue with highest priority first.
// Since Heap is a min-heap, we reverse the comparison.
pq := heap.NewIndexed(func(a, b *Item) int {
return cmp.Compare(b.priority, a.priority)
}, func(item *Item, i int) { item.index = i })
// Some items and their priorities.
items := map[string]int{
"banana": 3, "apple": 2, "pear": 4,
}
// Add the items to the priority queue.
for value, priority := range items {
pq.Insert(&Item{
value: value,
priority: priority,
})
}
// Insert a new item and then modify its priority.
item := &Item{
value: "orange",
priority: 1,
}
pq.Insert(item)
// Change the item's priority.
item.priority = 5
pq.Changed(item.index)
// Take the items out; they arrive in decreasing priority order.
for pq.Len() > 0 {
item := pq.TakeMin()
fmt.Printf("%.2d:%s ", item.priority, item.value)
}
}
Output: 05:orange 04:pear 03:banana 02:apple
Example (TopK) ¶
ExampleHeap_topK demonstrates finding the K largest elements using a min-heap and ChangeMin. This is the "top K" algorithm.
package main
import (
"cmp"
"fmt"
"github.com/jba/heap"
)
func main() {
// To find the K largest elements, use a min-heap of size K.
// The heap's min is the smallest of the K largest seen so far.
const K = 3
data := []int{7, 2, 9, 1, 5, 8, 3, 6, 4, 10}
h := heap.New(cmp.Compare[int])
// Initialize the heap with the first K elements.
// The heap will own data[:K], but we don't need to refer to that
// part of the slice any more.
h.Init(data[:K])
// For remaining elements, replace the min if we find a larger value.
for _, v := range data[K:] {
if v > h.Min() {
h.ChangeMin(v)
}
}
// Drain the heap to get the K largest (in ascending order).
fmt.Printf("%d largest elements:\n", K)
for v := range h.Drain() {
fmt.Println(v)
}
}
Output: 3 largest elements: 8 9 10
Index ¶
- type Heap
- func (h *Heap[T]) All() iter.Seq[T]
- func (h *Heap[T]) ChangeMin(v T)
- func (h *Heap[T]) Changed(i int)
- func (h *Heap[T]) Clear()
- func (h *Heap[T]) Delete(i int)
- func (h *Heap[T]) Drain() iter.Seq[T]
- func (h *Heap[T]) Init(s []T)
- func (h *Heap[T]) Insert(value T)
- func (h *Heap[T]) InsertAll(seq iter.Seq[T])
- func (h *Heap[T]) Len() int
- func (h *Heap[T]) Min() T
- func (h *Heap[T]) TakeMin() T
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Heap ¶
type Heap[T any] struct { // contains filtered or unexported fields }
A Heap is a binary min-heap.
Example ¶
package main
import (
"cmp"
"fmt"
"github.com/jba/heap"
)
func main() {
h := heap.New[int](cmp.Compare[int])
// Insert elements.
h.Init([]int{5, 3, 7, 1})
// Extract elements in sorted order.
fmt.Println(h.TakeMin())
fmt.Println(h.TakeMin())
fmt.Println(h.TakeMin())
fmt.Println(h.TakeMin())
}
Output: 1 3 5 7
func New ¶
New creates a new Heap with the given comparison function. The comparison function should return:
- a negative value if a < b
- zero if a == b
- a positive value if a > b.
func NewIndexed ¶ added in v0.8.0
NewIndexed creates a new Heap with the given comparison function and index function. The index function is called with an element and its current index in the heap whenever the element's position changes, or with -1 when the element is removed.
For the index function to work, all elements in the heap must be distinct.
A Heap created with NewIndexed supports the Heap.Delete and Heap.Changed methods.
func (*Heap[T]) All ¶
All returns an iterator over all elements in the heap in unspecified order.
Example ¶
package main
import (
"cmp"
"fmt"
"github.com/jba/heap"
)
func main() {
h := heap.New(cmp.Compare[int])
h.Init([]int{5, 3, 7, 1})
// Iterate over all elements.
sum := 0
for v := range h.All() {
sum += v
}
fmt.Printf("Total elements %d, sum %d\n", h.Len(), sum)
}
Output: Total elements 4, sum 16
func (*Heap[T]) ChangeMin ¶ added in v0.2.0
func (h *Heap[T]) ChangeMin(v T)
ChangeMin replaces the minimum value in the heap with the given value. It panics if the heap is empty.
func (*Heap[T]) Changed ¶ added in v0.4.0
Changed restores the heap property after the element at index i has been modified. The only reasonable values for i are 0, for the minimum element (but see Heap.ChangeMin for an alternative) or an index maintained by an index function (see NewIndexed). If i is out of range, or it is non-zero and there is no index function, Changed panics.
func (*Heap[T]) Delete ¶ added in v0.4.0
Delete removes the element at index i from the heap. The only reasonable values for i are 0, for the minimum element (but see Heap.TakeMin), or an index maintained by an index function (see NewIndexed). If i is out of range, or it is non-zero and there is no index function, Delete panics.
func (*Heap[T]) Drain ¶ added in v0.2.0
Drain removes and returns the heap elements in sorted order, from smallest to largest.
The result is undefined if the heap is changed during iteration.
func (*Heap[T]) Init ¶ added in v0.9.0
func (h *Heap[T]) Init(s []T)
Init creates a heap from the slice. The heap owns the slice: the caller must not use it subsequently. Init panics if the heap is not empty.
func (*Heap[T]) InsertAll ¶ added in v0.9.0
InsertAll adds all elements of the sequence to the heap, re-establishing the heap property at the end. It is more efficient to call InsertAll on a long sequence than it is to call Heap.Insert on each element of the sequence.
Example ¶
package main
import (
"cmp"
"fmt"
"slices"
"github.com/jba/heap"
)
func main() {
h := heap.New(cmp.Compare[int])
h.Init([]int{5, 3, 1})
// Add more elements to the existing heap.
h.InsertAll(slices.Values([]int{4, 2, 5, 6, 0}))
for v := range h.Drain() {
fmt.Println(v)
}
}
Output: 0 1 2 3 4 5 5 6