This commit is contained in:
2022-06-09 12:09:35 +01:00
commit 46ebc4396c
6 changed files with 397 additions and 0 deletions
+127
View File
@@ -0,0 +1,127 @@
package heap
import "golang.org/x/exp/constraints"
type HeapType bool
const (
MINHEAP HeapType = false
MAXHEAP HeapType = true
)
// Heap object for generic orderable (i.e. can be compared with < or >) data types
type Heap[Orderable constraints.Ordered] struct {
data []Orderable
heapSize int
}
// Parent index is returned for an input index
func Parent(index int) (parent int) {
return (index - 1) / 2
}
// Left index is returned for an input index
func Left(index int) (left int) {
return 2*index + 1
}
// Right index is returned for an input index
func Right(index int) (right int) {
return 2*index + 2
}
// exchange two items within the context of the heap. requires max/min heapify afterwards
func exchange[Orderable constraints.Ordered](h *Heap[Orderable], x, y int) {
h.data[x], h.data[y] = h.data[y], h.data[x]
}
// IsMaxHeap returns true when the heap satisfies the max heap property i.e. holds a valid structure for a max heap
func IsMaxHeap[Orderable constraints.Ordered](h *Heap[Orderable]) bool {
for index, val := range h.data {
if h.data[Parent(index)] < val {
return false
}
}
return true
}
// IsMinHeap returns true when the heap satisfies the min heap property i.e. holds a valid structure for a min heap
func IsMinHeap[Orderable constraints.Ordered](h *Heap[Orderable]) bool {
for index, val := range h.data {
if h.data[Parent(index)] > val {
return false
}
}
return true
}
// maxHeapify reorders into a min heap starting at the input index i
func maxHeapify[Orderable constraints.Ordered](h *Heap[Orderable], i int) {
l, r := Left(i), Right(i)
var largest int
if l < h.heapSize && h.data[l] > h.data[i] {
largest = l
} else {
largest = i
}
if r < h.heapSize && h.data[r] > h.data[largest] {
largest = r
}
if largest != i {
exchange(h, i, largest)
maxHeapify(h, largest)
}
}
// minHeapify reorders into a min heap starting at the input index i
func minHeapify[Orderable constraints.Ordered](h *Heap[Orderable], i int) {
l, r := Left(i), Right(i)
var smallest int
if l < h.heapSize && h.data[l] < h.data[i] {
smallest = l
} else {
smallest = i
}
if r < h.heapSize && h.data[r] < h.data[smallest] {
smallest = r
}
if smallest != i {
exchange(h, i, smallest)
minHeapify(h, smallest)
}
}
// BuildHeap takes a generic slice (any type that can be compared with < and >) and the type of heap and returns a pointer to a heap structure
func BuildHeap[Orderable constraints.Ordered](d []Orderable, maxHeap HeapType) *Heap[Orderable] {
heap := &Heap[Orderable]{d, len(d)}
for i := len(d) / 2; i >= 0; i-- {
if maxHeap {
maxHeapify(heap, i)
} else {
minHeapify(heap, i)
}
}
return heap
}
// HeapSort takes a generic slice (any type that can be compared with < and >) and returns the sorted slice
func HeapSort[Orderable constraints.Ordered](d []Orderable, maxHeap HeapType) []Orderable {
heap := BuildHeap(d, maxHeap)
for i := len(d) - 1; i > 0; i-- {
exchange(heap, 0, i)
heap.heapSize = heap.heapSize - 1
if maxHeap {
maxHeapify(heap, 0)
} else {
minHeapify(heap, 0)
}
}
return heap.data
}
+155
View File
@@ -0,0 +1,155 @@
package queue
import (
"fmt"
"reflect"
"git.wens.org.uk/heapqueue/pkg/heap"
"golang.org/x/exp/constraints"
)
//QueueType is an enum for min/max queue
type QueueType bool
const (
MINQUEUE QueueType = false
MAXQUEUE QueueType = true
)
// Queue data type, holding a slice of generic queue objects
type Queue[Orderable constraints.Ordered, T any] struct {
store []QueueObject[Orderable, T]
queueSize int
}
// QueueObject holds generic types for key (comparable with > and < only), and any for value
type QueueObject[Orderable constraints.Ordered, T any] struct {
Key Orderable
Value T
}
// BuildQueue takes an input slice of queue objects and the type of queue, returning a pointer to the constructed priority queue
func BuildQueue[Orderable constraints.Ordered, T any](d []QueueObject[Orderable, T], qType QueueType) *Queue[Orderable, T] {
q := &Queue[Orderable, T]{d, len(d)}
for i := len(d) / 2; i >= 0; i-- {
if qType == MAXQUEUE {
maxHeapify(q, i)
} else {
minHeapify(q, i)
}
}
return q
}
// exchange two items within the context of the queue. requires max/min heapify afterwards
func exchange[Orderable constraints.Ordered, T any](q *Queue[Orderable, T], x, y int) {
q.store[x], q.store[y] = q.store[y], q.store[x]
}
// maxHeapify reorders into a max heap starting at the input index i
func maxHeapify[Orderable constraints.Ordered, T any](q *Queue[Orderable, T], i int) {
l, r := heap.Left(i), heap.Right(i)
var largest int
if l < q.queueSize && q.store[l].Key > q.store[i].Key {
largest = l
} else {
largest = i
}
if r < q.queueSize && q.store[r].Key > q.store[largest].Key {
largest = r
}
if largest != i {
exchange(q, i, largest)
maxHeapify(q, largest)
}
}
// minHeapify reorders into a min heap starting at the input index i
func minHeapify[Orderable constraints.Ordered, T any](q *Queue[Orderable, T], i int) {
l, r := heap.Left(i), heap.Right(i)
var smallest int
if l < q.queueSize && q.store[l].Key < q.store[i].Key {
smallest = l
} else {
smallest = i
}
if r < q.queueSize && q.store[r].Key < q.store[smallest].Key {
smallest = r
}
if smallest != i {
exchange(q, i, smallest)
minHeapify(q, smallest)
}
}
// Maximum returns the QueueObject with the highest priority
func Maximum[Orderable constraints.Ordered, T any](q *Queue[Orderable, T]) (ret QueueObject[Orderable, T], e error) {
if q.queueSize < 1 {
e = fmt.Errorf("heap underflow")
return
}
ret = q.store[0]
return
}
// ExtractMaximum returns the QueueObject with the highest priority and removes it from the queue, reordering afterwards
func ExtractMaximum[Orderable constraints.Ordered, T any](q *Queue[Orderable, T]) (ret QueueObject[Orderable, T], e error) {
ret, e = Maximum(q)
if e != nil {
return
}
q.store[0] = q.store[q.queueSize-1]
q.queueSize--
q.store = q.store[0:q.queueSize]
maxHeapify(q, 0)
return
}
// IncraseKey raises the priority of a given queue item and reorders the queue
func IncreaseKey[Orderable constraints.Ordered, T any](q *Queue[Orderable, T], item QueueObject[Orderable, T], newKey Orderable) error {
if newKey < item.Key {
return fmt.Errorf("new key %v is smaller than current key %v", newKey, item.Key)
}
var i int
for idx, qObj := range q.store {
if reflect.DeepEqual(qObj, item) {
q.store[idx] = QueueObject[Orderable, T]{Key: newKey, Value: qObj.Value}
i = idx
}
}
for q.store[heap.Parent(i)].Key < q.store[i].Key {
exchange(q, i, heap.Parent(i))
i = heap.Parent(i)
}
return nil
}
// Insert adds a new item to the queue
func Insert[Orderable constraints.Ordered, T any](q *Queue[Orderable, T], item QueueObject[Orderable, T]) {
q.queueSize++
k := item.Key
insert := QueueObject[Orderable, T]{Value: item.Value}
q.store = append(q.store, insert)
IncreaseKey(q, insert, k)
}
// IsMaxQueue returns true when the queue satisfies the max queue property i.e. holds a valid structure for a max queue
func IsMaxQueue[Orderable constraints.Ordered, T any](q *Queue[Orderable, T]) bool {
for index, val := range q.store {
if q.store[heap.Parent(index)].Key < val.Key {
return false
}
}
return true
}