186 lines
3.4 KiB
Go
186 lines
3.4 KiB
Go
package main
|
|
|
|
import "math/bits"
|
|
|
|
type fibTree[T any] struct {
|
|
value *T
|
|
parent *fibTree[T]
|
|
child []*fibTree[T]
|
|
mark bool
|
|
}
|
|
|
|
func (t *fibTree[T]) Value() *T { return t.value }
|
|
func (t *fibTree[T]) addAtEnd(n *fibTree[T]) {
|
|
n.parent = t
|
|
t.child = append(t.child, n)
|
|
}
|
|
|
|
type fibHeap[T any] struct {
|
|
trees []*fibTree[T]
|
|
least *fibTree[T]
|
|
count uint
|
|
less func(a, b *T) bool
|
|
}
|
|
|
|
func FibHeap[T any](less func(a, b *T) bool) *fibHeap[T] {
|
|
return &fibHeap[T]{less: less}
|
|
}
|
|
|
|
func (h *fibHeap[T]) GetMin() *T {
|
|
return h.least.value
|
|
}
|
|
|
|
func (h *fibHeap[T]) IsEmpty() bool { return h.least == nil }
|
|
|
|
func (h *fibHeap[T]) Insert(v *T) {
|
|
ntree := &fibTree[T]{value: v}
|
|
h.trees = append(h.trees, ntree)
|
|
if h.least == nil || h.less(v, h.least.value) {
|
|
h.least = ntree
|
|
}
|
|
h.count++
|
|
}
|
|
|
|
func (h *fibHeap[T]) ExtractMin() *T {
|
|
smallest := h.least
|
|
if smallest != nil {
|
|
// Remove smallest from root trees.
|
|
for i := range h.trees {
|
|
pos := h.trees[i]
|
|
if pos == smallest {
|
|
h.trees[i] = h.trees[len(h.trees)-1]
|
|
h.trees = h.trees[:len(h.trees)-1]
|
|
break
|
|
}
|
|
}
|
|
|
|
// Add children to root
|
|
h.trees = append(h.trees, smallest.child...)
|
|
smallest.child = smallest.child[:0]
|
|
|
|
h.least = nil
|
|
if len(h.trees) > 0 {
|
|
h.consolidate()
|
|
}
|
|
|
|
h.count--
|
|
return smallest.value
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (h *fibHeap[T]) consolidate() {
|
|
aux := make([]*fibTree[T], bits.Len(h.count)+1)
|
|
for _, x := range h.trees {
|
|
order := len(x.child)
|
|
|
|
// consolidate the larger roots under smaller roots of same order until we have at most one tree per order.
|
|
for aux[order] != nil {
|
|
y := aux[order]
|
|
if h.less(y.value, x.value) {
|
|
x, y = y, x
|
|
}
|
|
x.addAtEnd(y)
|
|
aux[order] = nil
|
|
order++
|
|
}
|
|
aux[order] = x
|
|
}
|
|
|
|
h.trees = h.trees[:0]
|
|
// move ordered trees to root and find least node.
|
|
for _, k := range aux {
|
|
if k != nil {
|
|
k.parent = nil
|
|
h.trees = append(h.trees, k)
|
|
if h.least == nil || h.less(k.value, h.least.value) {
|
|
h.least = k
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (h *fibHeap[T]) Merge(a *fibHeap[T]) {
|
|
h.trees = append(h.trees, a.trees...)
|
|
h.count += a.count
|
|
if h.least == nil || a.least != nil && h.less(a.least.value, h.least.value) {
|
|
h.least = a.least
|
|
}
|
|
}
|
|
|
|
func (h *fibHeap[T]) find(fn func(*T) bool) *fibTree[T] {
|
|
var st []*fibTree[T]
|
|
st = append(st, h.trees...)
|
|
var tr *fibTree[T]
|
|
|
|
for len(st) > 0 {
|
|
tr, st = st[0], st[1:]
|
|
ro := *tr.value
|
|
if fn(&ro) {
|
|
break
|
|
}
|
|
st = append(st, tr.child...)
|
|
}
|
|
|
|
return tr
|
|
}
|
|
|
|
func (h *fibHeap[T]) Find(fn func(*T) bool) *T {
|
|
if needle := h.find(fn); needle != nil {
|
|
return needle.value
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (h *fibHeap[T]) DecreaseKey(find func(*T) bool, decrease func(*T)) {
|
|
needle := h.find(find)
|
|
if needle == nil {
|
|
return
|
|
}
|
|
decrease(needle.value)
|
|
|
|
if h.less(needle.value, h.least.value) {
|
|
h.least = needle
|
|
}
|
|
|
|
if parent := needle.parent; parent != nil {
|
|
if h.less(needle.value, parent.value) {
|
|
h.cut(needle)
|
|
h.cascadingCut(parent)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (h *fibHeap[T]) cut(x *fibTree[T]) {
|
|
parent := x.parent
|
|
for i := range parent.child {
|
|
pos := parent.child[i]
|
|
if pos == x {
|
|
parent.child[i] = parent.child[len(parent.child)-1]
|
|
parent.child = parent.child[:len(parent.child)-1]
|
|
break
|
|
}
|
|
}
|
|
|
|
x.parent = nil
|
|
x.mark = false
|
|
h.trees = append(h.trees, x)
|
|
|
|
if h.less(x.value, h.least.value) {
|
|
h.least = x
|
|
}
|
|
}
|
|
|
|
func (h *fibHeap[T]) cascadingCut(y *fibTree[T]) {
|
|
if y.parent != nil {
|
|
if !y.mark {
|
|
y.mark = true
|
|
return
|
|
}
|
|
|
|
h.cut(y)
|
|
h.cascadingCut(y.parent)
|
|
}
|
|
}
|