heap

package module
v0.9.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 1, 2026 License: BSD-3-Clause Imports: 2 Imported by: 0

README

Heaps

Implementation to go along with the proposal for container/heap/v2.

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

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

func New[T any](compare func(T, T) int) *Heap[T]

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

func NewIndexed[T any](compare func(T, T) int, setIndex func(T, int)) *Heap[T]

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

func (h *Heap[T]) All() iter.Seq[T]

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

func (h *Heap[T]) Changed(i int)

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]) Clear

func (h *Heap[T]) Clear()

Clear removes all elements from the heap.

func (*Heap[T]) Delete added in v0.4.0

func (h *Heap[T]) Delete(i int)

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

func (h *Heap[T]) Drain() iter.Seq[T]

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]) Insert

func (h *Heap[T]) Insert(value T)

Insert adds an element to the heap.

func (*Heap[T]) InsertAll added in v0.9.0

func (h *Heap[T]) InsertAll(seq iter.Seq[T])

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

func (*Heap[T]) Len

func (h *Heap[T]) Len() int

Len returns the number of elements in the heap.

func (*Heap[T]) Min

func (h *Heap[T]) Min() T

Min returns the minimum element in the heap without removing it. It panics if the heap is empty.

func (*Heap[T]) TakeMin added in v0.2.0

func (h *Heap[T]) TakeMin() T

TakeMin removes and returns the minimum element from the heap. It panics if the heap is empty.

Directories

Path Synopsis
internal
plot_build command
plot_insert command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL