Fibonacci heap: Difference between revisions
Line 845: | Line 845: | ||
node.right.left = node.left |
node.right.left = node.left |
||
end |
end |
||
function delete!(root, node) |
function delete!(root, node) |
||
if (parent = node.parent) == nothing |
if (parent = node.parent) == nothing |
||
Line 854: | Line 854: | ||
else |
else |
||
remove_from_child_list(root, parent, node) |
remove_from_child_list(root, parent, node) |
||
end |
|||
if root.rootlist != nothing |
|||
root.nodecount -= 1 |
|||
root.minnode = root.rootlist |
|||
for n in aslist(root.rootlist) |
|||
if n != nothing && n.value < root.minnode.value |
|||
root.minnode = n |
|||
end |
|||
end |
|||
end |
end |
||
end |
end |
||
Line 884: | Line 893: | ||
Delete(h3, xkeys[3]) |
Delete(h3, xkeys[3]) |
||
print(h3) |
print(h3) |
||
println("The minimum of h3 is now: ", Minimum(h3).value |
|||
</lang>{{out}} |
</lang>{{out}} |
||
<pre> |
<pre> |
||
Line 919: | Line 929: | ||
│ └─╴time |
│ └─╴time |
||
└─╴now |
└─╴now |
||
The minimum of h3 is now: good |
|||
</pre> |
</pre> |
||
Revision as of 06:37, 23 February 2020
This page uses content from Wikipedia. The original article was at Fibonacci heap. The list of authors can be seen in the page history. As with Rosetta Code, the text of Wikipedia is available under the GNU FDL. (See links for details on variance) |
- Task
- Implement queue operations for Fibonacci heaps. Where H is heap, x node with data value, k integer.
- Operations:
- MakeHeap() - create new empty Fibonacci heap
- Insert(H,x) - insert new element x into heap H
- Union(H1, H2) - union heap H1 and heap H2
- Minimum(H) - return minimum value from heap H
- ExtractMin(H) - (or DeleteMin(H)) - return minimum value from heap H and remove it from heap
- DecreaseKey(H,x,k) - decrease value of element x in heap H to value k
- Delete(H,x) - remove element x from heap H
C++
<lang cpp>template <class V> class FibonacciHeap;
template <class V> struct node { private: node<V>* prev; node<V>* next; node<V>* child; node<V>* parent; V value; int degree; bool marked; public: friend class FibonacciHeap<V>; node<V>* getPrev() {return prev;} node<V>* getNext() {return next;} node<V>* getChild() {return child;} node<V>* getParent() {return parent;} V getValue() {return value;} bool isMarked() {return marked;}
bool hasChildren() {return child;} bool hasParent() {return parent;} };
template <class V> class FibonacciHeap { protected: node<V>* heap; public:
FibonacciHeap() { heap=_empty(); } virtual ~FibonacciHeap() { if(heap) { _deleteAll(heap); } } node<V>* insert(V value) { node<V>* ret=_singleton(value); heap=_merge(heap,ret); return ret; } void merge(FibonacciHeap& other) { heap=_merge(heap,other.heap); other.heap=_empty(); }
bool isEmpty() { return heap==NULL; }
V getMinimum() { return heap->value; }
V removeMinimum() { node<V>* old=heap; heap=_removeMinimum(heap); V ret=old->value; delete old; return ret; }
void decreaseKey(node<V>* n,V value) { heap=_decreaseKey(heap,n,value); }
node<V>* find(V value) { return _find(heap,value); } private: node<V>* _empty() { return NULL; }
node<V>* _singleton(V value) { node<V>* n=new node<V>; n->value=value; n->prev=n->next=n; n->degree=0; n->marked=false; n->child=NULL; n->parent=NULL; return n; }
node<V>* _merge(node<V>* a,node<V>* b) { if(a==NULL)return b; if(b==NULL)return a; if(a->value>b->value) { node<V>* temp=a; a=b; b=temp; } node<V>* an=a->next; node<V>* bp=b->prev; a->next=b; b->prev=a; an->prev=bp; bp->next=an; return a; }
void _deleteAll(node<V>* n) { if(n!=NULL) { node<V>* c=n; do { node<V>* d=c; c=c->next; _deleteAll(d->child); delete d; } while(c!=n); } }
void _addChild(node<V>* parent,node<V>* child) { child->prev=child->next=child; child->parent=parent; parent->degree++; parent->child=_merge(parent->child,child); }
void _unMarkAndUnParentAll(node<V>* n) { if(n==NULL)return; node<V>* c=n; do { c->marked=false; c->parent=NULL; c=c->next; }while(c!=n); }
node<V>* _removeMinimum(node<V>* n) { _unMarkAndUnParentAll(n->child); if(n->next==n) { n=n->child; } else { n->next->prev=n->prev; n->prev->next=n->next; n=_merge(n->next,n->child); } if(n==NULL)return n; node<V>* trees[64]={NULL};
while(true) { if(trees[n->degree]!=NULL) { node<V>* t=trees[n->degree]; if(t==n)break; trees[n->degree]=NULL; if(n->value<t->value) { t->prev->next=t->next; t->next->prev=t->prev; _addChild(n,t); } else { t->prev->next=t->next; t->next->prev=t->prev; if(n->next==n) { t->next=t->prev=t; _addChild(t,n); n=t; } else { n->prev->next=t; n->next->prev=t; t->next=n->next; t->prev=n->prev; _addChild(t,n); n=t; } } continue; } else { trees[n->degree]=n; } n=n->next; } node<V>* min=n; do { if(n->value<min->value)min=n; n=n->next; } while(n!=n); return min; }
node<V>* _cut(node<V>* heap,node<V>* n) { if(n->next==n) { n->parent->child=NULL; } else { n->next->prev=n->prev; n->prev->next=n->next; n->parent->child=n->next; } n->next=n->prev=n; n->marked=false; return _merge(heap,n); }
node<V>* _decreaseKey(node<V>* heap,node<V>* n,V value) { if(n->value<value)return heap; n->value=value; if(n->value<n->parent->value) { heap=_cut(heap,n); node<V>* parent=n->parent; n->parent=NULL; while(parent!=NULL && parent->marked) { heap=_cut(heap,parent); n=parent; parent=n->parent; n->parent=NULL; } if(parent!=NULL && parent->parent!=NULL)parent->marked=true; } return heap; }
node<V>* _find(node<V>* heap,V value) { node<V>* n=heap; if(n==NULL)return NULL; do { if(n->value==value)return n; node<V>* ret=_find(n->child,value); if(ret)return ret; n=n->next; }while(n!=heap); return NULL; } };</lang>
Go
A package. Implementation follows Fredman and Tarjan's 1987 paper. <lang go>package fib
import "fmt"
type Value interface {
LT(Value) bool
}
type Node struct {
value Value parent *Node child *Node prev, next *Node rank int mark bool
}
func (n Node) Value() Value { return n.value }
type Heap struct{ *Node }
// task requirement func MakeHeap() *Heap { return &Heap{} }
// task requirement func (h *Heap) Insert(v Value) *Node {
x := &Node{value: v} if h.Node == nil { x.next = x x.prev = x h.Node = x } else { meld1(h.Node, x) if x.value.LT(h.value) { h.Node = x } } return x
}
func meld1(list, single *Node) {
list.prev.next = single single.prev = list.prev single.next = list list.prev = single
}
// task requirement func (h *Heap) Union(h2 *Heap) {
switch { case h.Node == nil: *h = *h2 case h2.Node != nil: meld2(h.Node, h2.Node) if h2.value.LT(h.value) { *h = *h2 } } h2.Node = nil
}
func meld2(a, b *Node) {
a.prev.next = b b.prev.next = a a.prev, b.prev = b.prev, a.prev
}
// task requirement func (h Heap) Minimum() (min Value, ok bool) {
if h.Node == nil { return } return h.value, true
}
// task requirement func (h *Heap) ExtractMin() (min Value, ok bool) {
if h.Node == nil { return } min = h.value roots := map[int]*Node{} add := func(r *Node) { r.prev = r r.next = r for { x, ok := roots[r.rank] if !ok { break } delete(roots, r.rank) if x.value.LT(r.value) { r, x = x, r } x.parent = r x.mark = false if r.child == nil { x.next = x x.prev = x r.child = x } else { meld1(r.child, x) } r.rank++ } roots[r.rank] = r } for r := h.next; r != h.Node; { n := r.next add(r) r = n } if c := h.child; c != nil { c.parent = nil r := c.next add(c) for r != c { n := r.next r.parent = nil add(r) r = n } } if len(roots) == 0 { h.Node = nil return min, true } var mv *Node var d int for d, mv = range roots { break } delete(roots, d) mv.next = mv mv.prev = mv for _, r := range roots { r.prev = mv r.next = mv.next mv.next.prev = r mv.next = r if r.value.LT(mv.value) { mv = r } } h.Node = mv return min, true
}
// task requirement func (h *Heap) DecreaseKey(n *Node, v Value) error {
if n.value.LT(v) { return fmt.Errorf("DecreaseKey new value greater than existing value") } n.value = v if n == h.Node { return nil } p := n.parent if p == nil { if v.LT(h.value) { h.Node = n } return nil } h.cutAndMeld(n) return nil
}
func (h Heap) cut(x *Node) {
p := x.parent p.rank-- if p.rank == 0 { p.child = nil } else { p.child = x.next x.prev.next = x.next x.next.prev = x.prev } if p.parent == nil { return } if !p.mark { p.mark = true return } h.cutAndMeld(p)
}
func (h Heap) cutAndMeld(x *Node) {
h.cut(x) x.parent = nil meld1(h.Node, x)
}
// task requirement func (h *Heap) Delete(n *Node) {
p := n.parent if p == nil { if n == h.Node { h.ExtractMin() return } n.prev.next = n.next n.next.prev = n.prev } else { h.cut(n) } c := n.child if c == nil { return } for { c.parent = nil c = c.next if c == n.child { break } } meld2(h.Node, c)
}
// adapted from task "Visualize a tree" func (h Heap) Vis() {
if h.Node == nil { fmt.Println("<empty>") return } var f func(*Node, string) f = func(n *Node, pre string) { pc := "│ " for x := n; ; x = x.next { if x.next != n { fmt.Print(pre, "├─") } else { fmt.Print(pre, "└─") pc = " " } if x.child == nil { fmt.Println("╴", x.value) } else { fmt.Println("┐", x.value) f(x.child, pre+pc) } if x.next == n { break } } } f(h.Node, "")
}</lang> A demonstration: <lang go>package main
import (
"fmt"
"fib"
)
type str string
func (s str) LT(t fib.Value) bool { return s < t.(str) }
func main() {
fmt.Println("MakeHeap:") h := fib.MakeHeap() h.Vis()
fmt.Println("\nInsert:") h.Insert(str("cat")) h.Vis()
fmt.Println("\nUnion:") h2 := fib.MakeHeap() h2.Insert(str("rat")) h.Union(h2) h.Vis()
fmt.Println("\nMinimum:") m, _ := h.Minimum() fmt.Println(m)
fmt.Println("\nExtractMin:") // add a couple more items to demonstrate parent-child linking that // happens on delete min. h.Insert(str("bat")) x := h.Insert(str("meerkat")) // save x for decrease key and delete demos m, _ = h.ExtractMin() fmt.Printf("(extracted %v)\n", m) h.Vis()
fmt.Println("\nDecreaseKey:") h.DecreaseKey(x, str("gnat")) h.Vis() fmt.Println("\nDelete:") // add yet a couple more items to show how F&T's original delete was // lazier than CLRS's delete. h.Insert(str("bobcat")) h.Insert(str("bat")) fmt.Printf("(deleting %v)\n", x.Value()) h.Delete(x) h.Vis()
}</lang>
- Output:
MakeHeap: <empty> Insert: └─╴ cat Union: ├─╴ cat └─╴ rat Minimum: cat ExtractMin: (extracted bat) ├─┐ cat │ └─╴ rat └─╴ meerkat DecreaseKey: ├─┐ cat │ └─╴ rat └─╴ gnat Delete: (deleting gnat) ├─╴ bat ├─╴ bobcat └─┐ cat └─╴ rat
Julia
<lang julia>module FibonacciHeaps
export FNode, FibonacciHeap, insert, extractmin, findmin, decreasekey, delete! export Insert, MakeHeap, Minimum, ExtractMin, DecreaseKey, Delete import Base.print
mutable struct FNode{T}
value::T degree::Int parent::Union{FNode, Nothing} child::Union{FNode, Nothing} left::Union{FNode, Nothing} right::Union{FNode, Nothing} mark::Bool
end FNode(data::T) where T = FNode{T}(data, 0, nothing, nothing, nothing, nothing, false)
- Get list of nodes attached to head (of a circular doubly linked list)
function aslist(head::FNode)
nodelist, node, stop = FNode[], head, head flag = false while true if node == stop flag && break flag = true end push!(nodelist, node) node = node.right end return nodelist
end
mutable struct FibonacciHeap
rootlist::Union{FNode, Nothing} minnode::Union{FNode, Nothing} nodecount::Int FibonacciHeap() = new(nothing, nothing, 0)
end MakeHeap() = FibonacciHeap() # MakeHeap() for task
function print(io::IO, h::FibonacciHeap)
if h.rootlist == nothing println("<empty heap>") return end function printtree(io::IO, rootnode, s::String="") n = rootnode stem= "│ " while n != nothing if n.right != rootnode print(io, s, "├─") else print(io, s, "└─") stem = " " end if n.child == nothing println(io, "╴", n.value) else println(io, "┐", n.value) printtree(io, n.child, s * stem) end if n.right == rootnode break end n = n.right end end printtree(io, h.rootlist)
end
- return min node in O(1) time
findmin(h::FibonacciHeap) = h.minnode Minimum(H) = findmin(H) # Minimum(H) for task
- extract (delete) the min node from the heap in O(log n) time
function extractmin(root::FibonacciHeap)
z = root.minnode if z != nothing if z.child != nothing # attach child nodes to root list children = aslist(z.child) for c in children merge_with_root_list(root, c) c.parent = nothing end end remove_from_root_list(root, z) # set new min node in heap if z == z.right root.minnode = root.rootlist = nothing else root.minnode = z.right consolidate(root) end root.nodecount -= 1 end return z
end ExtractMin(H) = extractmin(H) # ExtractMin(H) for task
- insert new node into the unordered root list in O(1) time
function insert(root, data)
n = FNode(data) n.left = n.right = n merge_with_root_list(root, n) if root.minnode == nothing || n.value < root.minnode.value root.minnode = n end root.nodecount += 1 return n
end Insert(H, x) = insert(H, x) # Insert(H, x) for task
- modify the data of some node in the heap in O(1) time
function decreasekey(root, x, k)
if k > x.value return nothing end x.value = k y = x.parent if y != nothing && x.value < y.value cut(root, x, y) cascadingcut(root, y) end if x.value < root.minnode.value root.minnode = x end
end DecreaseKey(H, x, k) = decreasekey(H, x, k) # DecreaseKey(H, x, k)
- merge two fibonacci heaps in O(1) time by concatenating the root lists
- the root of the new root list becomes equal to the first list and the second
- list is simply appended to the end (then the proper min node is determined)
function merge(h1, h2)
newh = FibonacciHeap() newh.rootlist, newh.minnode = h1.rootlist, h1.minnode # fix pointers when merging the two heaps last = h2.rootlist.left h2.rootlist.left = newh.rootlist.left newh.rootlist.left.right = h2.rootlist newh.rootlist.left = last newh.rootlist.left.right = newh.rootlist # update min node if needed if h2.minnode.value < newh.minnode.value newh.min_node = h2.minnode end # update total nodes newh.nodecount = h1.nodecount + h2.nodecount return newh
end Union(H1, H2) = merge(H1, H2) # NB: Union is a type in Julia # Union(H1, H2) for task
- if a child node becomes smaller than its parent node we
- cut this child node off and bring it up to the root list
function cut(root, x, y)
remove_from_child_list(root, y, x) y.degree -= 1 merge_with_root_list(root, x) x.parent = nothing x.mark = false
end
- cascading cut of parent node to obtain good time bounds
function cascadingcut(root, y)
z = y.parent if z != nothing if y.mark == false y.mark = true else cut(root, y, z) cascadingcut(root, z) end end
end
- combine root nodes of equal degree to consolidate the heap
- by creating a list of unordered binomial trees
function consolidate(root)
nodes = aslist(root.rootlist) len = length(nodes) A = fill!(Vector{Union{FNode, Nothing}}(undef, Int(round(log(root.nodecount)) * 2)), nothing) for x in nodes d = x.degree + 1 while A[d] != nothing y = A[d] if x.value > y.value x, y = y, x end heaplink(root, y, x) A[d] = nothing d += 1 end A[d] = x end # find new min node - no need to reconstruct new root list below # because root list was iteratively changing as we were moving # nodes around in the above loop for nod in A if nod != nothing && nod.value < root.minnode.value root.minnode = nod end end
end
- actual linking of one node to another in the root list
- while also updating the child linked list
function heaplink(root, y, x)
remove_from_root_list(root, y) y.left = y.right = y merge_with_child_list(root, x, y) x.degree += 1 y.parent = x y.mark = false
end
- merge a node with the doubly linked root list
function merge_with_root_list(root, node)
if root.rootlist == nothing root.rootlist = node else node.right = root.rootlist.right node.left = root.rootlist root.rootlist.right.left = node root.rootlist.right = node end
end
- merge a node with the doubly linked child list of a root node
function merge_with_child_list(root, parent, node)
if parent.child == nothing parent.child = node else node.right = parent.child.right node.left = parent.child parent.child.right.left = node parent.child.right = node end
end
- remove a node from the doubly linked root list
function remove_from_root_list(root, node)
if node == root.rootlist root.rootlist = node.right end node.left.right = node.right node.right.left = node.left
end
- remove a node from the doubly linked child list
function remove_from_child_list(root, parent, node)
if parent.child == parent.child.right parent.child = nothing elseif parent.child == node parent.child = node.right node.right.parent = parent end node.left.right = node.right node.right.left = node.left
end
function delete!(root, node)
if (parent = node.parent) == nothing if node.child != nothing cut(root, node.child, node) end remove_from_root_list(root, node) else remove_from_child_list(root, parent, node) end if root.rootlist != nothing root.nodecount -= 1 root.minnode = root.rootlist for n in aslist(root.rootlist) if n != nothing && n.value < root.minnode.value root.minnode = n end end end
end Delete(H, x) = delete!(H, x) # Delete(H, x) for task
end # module
using .FibonacciHeaps
const h1 = MakeHeap() println("Made heap 1:"), print(h1) Insert(h1, "now") println("Inserted the word now into heap 1"), print(h1) const h2 = MakeHeap() println("Made another heap 2.") const t = Insert(h2, "time") println("Inserted the word time into heap 2:"), print(h2) const h3 = Union(h1, h2) println("Made heap 3, union of heap 1 and heap 2:"), print(h3) println("The minimum of h3 is now \"$(Minimum(h3).value)\".") const xkeys = [Insert(h3, x) for x in ["all", "good", "men"]] println("Inserted 3 more into h3:"), print(h3) println("The minimum of h3 is now \"$(Minimum(h3).value)\".") println("The extracted min from heap 3 is: ", ExtractMin(h3).value) println("h3 is now:"), print(h3) println("Decrease key of heap 3 value $(xkeys[3].value) with the word come:") DecreaseKey(h3, xkeys[3], "come") print(h3) println("Delete node with value $(xkeys[3].value) from heap 3:") Delete(h3, xkeys[3]) print(h3) println("The minimum of h3 is now: ", Minimum(h3).value
</lang>
- Output:
Made heap 1: <empty heap> Inserted the word now into heap 1 └─╴now Made another heap 2. Inserted the word time into heap 2: └─╴time Made heap 3, union of heap 1 and heap 2: ├─╴now └─╴time The minimum of h3 is now "now". Inserted 3 more into h3: ├─╴now ├─╴men ├─╴good ├─╴all └─╴time The minimum of h3 is now "all". The extracted min from heap 3 is: all h3 is now: └─┐good ├─╴time └─┐men └─╴now Decrease key of heap 3 value men with the word come: ├─┐good │ └─╴time └─┐come └─╴now Delete node with value come from heap 3: ├─┐good │ └─╴time └─╴now The minimum of h3 is now: good
Kotlin
<lang scala>// version 1.2.21
class Node<V : Comparable<V>>(var value: V) {
var parent: Node<V>? = null var child: Node<V>? = null var prev: Node<V>? = null var next: Node<V>? = null var rank = 0 var mark = false
fun meld1(node: Node<V>) { this.prev?.next = node node.prev = this.prev node.next = this this.prev = node }
fun meld2(node: Node<V>) { this.prev?.next = node node.prev?.next = this val temp = this.prev this.prev = node.prev node.prev = temp }
}
// task requirement fun <V: Comparable<V>> makeHeap() = FibonacciHeap<V>()
class FibonacciHeap<V: Comparable<V>>(var node: Node<V>? = null) {
// task requirement fun insert(v: V): Node<V> { val x = Node(v) if (this.node == null) { x.next = x x.prev = x this.node = x } else { this.node!!.meld1(x) if (x.value < this.node!!.value) this.node = x } return x }
// task requirement fun union(other: FibonacciHeap<V>) { if (this.node == null) { this.node = other.node } else if (other.node != null) { this.node!!.meld2(other.node!!) if (other.node!!.value < this.node!!.value) this.node = other.node } other.node = null }
// task requirement fun minimum(): V? = this.node?.value
// task requirement fun extractMin(): V? { if (this.node == null) return null val min = minimum() val roots = mutableMapOf<Int, Node<V>>()
fun add(r: Node<V>) { r.prev = r r.next = r var rr = r while (true) { var x = roots[rr.rank] ?: break roots.remove(rr.rank) if (x.value < rr.value) { val t = rr rr = x x = t } x.parent = rr x.mark = false if (rr.child == null) { x.next = x x.prev = x rr.child = x } else { rr.child!!.meld1(x) } rr.rank++ } roots[rr.rank] = rr }
var r = this.node!!.next while (r != this.node) { val n = r!!.next add(r) r = n } val c = this.node!!.child if (c != null) { c.parent = null var rr = c.next!! add(c) while (rr != c) { val n = rr.next!! rr.parent = null add(rr) rr = n } } if (roots.isEmpty()) { this.node = null return min } val d = roots.keys.first() var mv = roots[d]!! roots.remove(d) mv.next = mv mv.prev = mv for ((_, rr) in roots) { rr.prev = mv rr.next = mv.next mv.next!!.prev = rr mv.next = rr if (rr.value < mv.value) mv = rr } this.node = mv return min }
// task requirement fun decreaseKey(n: Node<V>, v: V) { require (n.value > v) { "In 'decreaseKey' new value greater than existing value" } n.value = v if (n == this.node) return val p = n.parent if (p == null) { if (v < this.node!!.value) this.node = n return } cutAndMeld(n) }
private fun cut(x: Node<V>) { val p = x.parent if (p == null) return p.rank-- if (p.rank == 0) { p.child = null } else { p.child = x.next x.prev?.next = x.next x.next?.prev = x.prev } if (p.parent == null) return if (!p.mark) { p.mark = true return } cutAndMeld(p) }
private fun cutAndMeld(x: Node<V>) { cut(x) x.parent = null this.node?.meld1(x) }
// task requirement fun delete(n: Node<V>) { val p = n.parent if (p == null) { if (n == this.node) { extractMin() return } n.prev?.next = n.next n.next?.prev = n.prev } else { cut(n) } var c = n.child if (c == null) return while (true) { c!!.parent = null c = c.next if (c == n.child) break } this.node?.meld2(c!!) }
fun visualize() { if (this.node == null) { println("<empty>") return }
fun f(n: Node<V>, pre: String) { var pc = "│ " var x = n while (true) { if (x.next != n) { print("$pre├─") } else { print("$pre└─") pc = " " } if (x.child == null) { println("╴ ${x.value}") } else { println("┐ ${x.value}") f(x.child!!, pre + pc) } if (x.next == n) break x = x.next!! } } f(this.node!!, "") }
}
fun main(args: Array<String>) {
println("MakeHeap:") val h = makeHeap<String>() h.visualize()
println("\nInsert:") h.insert("cat") h.visualize()
println("\nUnion:") val h2 = makeHeap<String>() h2.insert("rat") h.union(h2) h.visualize()
println("\nMinimum:") var m = h.minimum() println(m)
println("\nExtractMin:") // add a couple more items to demonstrate parent-child linking that // happens on delete min. h.insert("bat") val x = h.insert("meerkat") // save x for decrease key and delete demos. m = h.extractMin() println("(extracted $m)") h.visualize()
println("\nDecreaseKey:") h.decreaseKey(x, "gnat") h.visualize()
println("\nDelete:") // add a couple more items. h.insert("bobcat") h.insert("bat") println("(deleting ${x.value})") h.delete(x) h.visualize()
}</lang>
- Output:
MakeHeap: <empty> Insert: └─╴ cat Union: ├─╴ cat └─╴ rat Minimum: cat ExtractMin: (extracted bat) ├─┐ cat │ └─╴ rat └─╴ meerkat DecreaseKey: ├─┐ cat │ └─╴ rat └─╴ gnat Delete: (deleting gnat) ├─╴ bat ├─╴ bobcat └─┐ cat └─╴ rat
Phix
<lang Phix>enum VALUE, PARENT, CHILD, PREV, NEXT, RANK, MARK, NODELEN=$
function new_node()
return repeat(NULL,NODELEN)
end function
sequence nodes = {} integer freelist = NULL
function new_slot()
integer res if freelist!=NULL then res = freelist freelist = nodes[freelist] nodes[freelist] = NULL else nodes = append(nodes,NULL) res = length(nodes) end if return res
end function
procedure release_slot(integer n)
nodes[n] = freelist freelist = n
end procedure
-- task requirement function MakeHeap()
return new_slot()
end function
procedure meld1(integer list, single)
nodes[nodes[list][PREV]][NEXT] = single nodes[single][PREV] = nodes[list][PREV] nodes[single][NEXT] = list nodes[list][PREV] = single
end procedure
-- task requirement function Insert(integer h, object v)
integer n = 0 sequence x = new_node() x[VALUE] = v if nodes[h] == NULL then x[NEXT] = h x[PREV] = h nodes[h] = x else n = new_slot() nodes[n] = x meld1(h, n) if nodes[n][VALUE]<nodes[h][VALUE] then h = n end if end if return {h,n}
end function
procedure meld2(integer a, b)
nodes[nodes[a][PREV]][NEXT] = b nodes[nodes[b][PREV]][NEXT] = a {nodes[a][PREV], nodes[b][PREV]} = {nodes[b][PREV], nodes[a][PREV]}
end procedure
-- task requirement function Union(integer h, h2)
if nodes[h] == NULL then h = h2 elsif nodes[h2] != NULL then meld2(h, h2) if nodes[h2][VALUE]<nodes[h][VALUE] then h = h2 end if else release_slot(h2) end if return {h,NULL} -- (h2:=NULL implied)
end function
-- task requirement function Minimum(integer h)
if nodes[h] == NULL then return {"<none>",false} end if return {nodes[h][VALUE], true}
end function
procedure add_roots(integer r, integer roots)
nodes[r][PREV] = r nodes[r][NEXT] = r while true do integer node = getd_index(nodes[r][RANK],roots) if node=NULL then exit end if integer x = getd_by_index(node,roots) deld(nodes[r][RANK],roots) if nodes[x][VALUE]<nodes[r][VALUE] then {r, x} = {x, r} end if nodes[x][PARENT] = r nodes[x][MARK] = false if nodes[r][CHILD] == NULL then nodes[x][NEXT] = x nodes[x][PREV] = x nodes[r][CHILD] = x else meld1(nodes[r][CHILD], x) end if nodes[r][RANK] += 1 end while setd(nodes[r][RANK],r,roots)
end procedure
-- task requirement function ExtractMin(integer h)
if nodes[h] == NULL then return {h,"<none>",false} end if object minimum = nodes[h][VALUE] integer roots = new_dict() integer r = nodes[h][NEXT], n while r != h do n := nodes[r][NEXT] add_roots(r,roots) r = n end while integer c = nodes[h][CHILD] if c != NULL then nodes[c][PARENT] = NULL r := nodes[c][NEXT] add_roots(c,roots) while r != c do n := nodes[r][NEXT] nodes[r][PARENT] = NULL add_roots(r,roots) r = n end while end if if dict_size(roots) == 0 then destroy_dict(roots) return {NULL, minimum, true} end if integer d = getd_partial_key(0,roots) integer mv = getd(d,roots) deld(d,roots) nodes[mv][NEXT] = mv nodes[mv][PREV] = mv sequence rs = getd_all_keys(roots) for i=1 to length(rs) do r = getd(rs[i],roots) nodes[r][PREV] = mv nodes[r][NEXT] = nodes[mv][NEXT] nodes[nodes[mv][NEXT]][PREV] = r nodes[mv][NEXT] = r if nodes[r][VALUE]<nodes[mv][VALUE] then mv = r end if end for h = mv destroy_dict(roots) return {h, minimum, true}
end function
procedure cut_and_meld(integer h, x, bool meld)
integer p := nodes[x][PARENT] nodes[p][RANK] -= 1 if nodes[p][RANK] == 0 then nodes[p][CHILD] = NULL else nodes[p][CHILD] = nodes[x][NEXT] nodes[nodes[x][PREV]][NEXT] = nodes[x][NEXT] nodes[nodes[x][NEXT]][PREV] = nodes[x][PREV] end if if nodes[p][PARENT] == NULL then return end if if not nodes[p][MARK] then nodes[p][MARK] = true return end if cut_and_meld(h,p,true) if meld then nodes[x][PARENT] = NULL meld1(h, x) end if
end procedure
-- task requirement function DecreaseKey(integer h, n, object v)
if nodes[n][VALUE]<v then crash("DecreaseKey new value greater than existing value") end if nodes[n][VALUE] = v if n!=h then integer p := nodes[n][PARENT] if p == NULL then if v<nodes[h][VALUE] then h = n end if else cut_and_meld(h,n,true) end if end if return h
end function
-- task requirement function Delete(integer h, n)
integer p := nodes[n][PARENT] if p == NULL then if n == h then {h} = ExtractMin(h) return h end if nodes[nodes[n][PREV]][NEXT] = nodes[n][NEXT] nodes[nodes[n][NEXT]][PREV] = nodes[n][PREV] else cut_and_meld(h,n,false) end if integer c := nodes[n][CHILD] if c != NULL then while true do nodes[c][PARENT] = NULL c = nodes[c][NEXT] if c == nodes[n][CHILD] then exit end if end while meld2(h, c) end if return h
end function
constant W=platform()=WINDOWS,
Horizontal = iff(W?#C4:'-'), Vertical = iff(W?#B3:'|'), sBtmLeft = iff(W?#C0:'+'), sLeftTee = iff(W?#C3:'+'), sTopRight = iff(W?#BF:'+')
procedure vis(integer n, string pre)
string pc = Vertical&" " sequence x = nodes[n] while true do integer next = x[NEXT] if next!=n then printf(1,pre&sLeftTee&Horizontal) else printf(1,pre&sBtmLeft&Horizontal) pc = " " end if if x[CHILD] == NULL then printf(1,"%c %s\n",{Horizontal,sprint(x[VALUE])}) else printf(1,"%c %s\n",{sTopRight,sprint(x[VALUE])}) vis(x[CHILD], pre&pc) end if if next=n then exit end if x = nodes[next] end while
end procedure
procedure Vis(integer h)
if nodes[h] == NULL then printf(1,"<empty>\n") return end if vis(h,"")
end procedure
printf(1,"MakeHeap:\n") integer h := MakeHeap() Vis(h)
printf(1,"\nInsert:\n") {h} = Insert(h,"cat") Vis(h)
printf(1,"\nUnion:\n") integer h2 := MakeHeap() {h2} = Insert(h2,"rat") {h,h2} = Union(h,h2) -- (h2:=NULL) Vis(h)
printf(1,"\nMinimum:\n") {object m, {}} = Minimum(h) ?m
printf(1,"\nExtractMin:\n") -- add a couple more items to demonstrate parent-child linking that -- happens on delete min. {h} = Insert(h,"bat") {h,integer x} = Insert(h,"meerkat") -- save x for decrease key and delete demos {h,m,{}} = ExtractMin(h) printf(1,"(extracted %s)\n", {sprint(m)}) Vis(h)
printf(1,"\nDecreaseKey:\n") h = DecreaseKey(h, x, "gnat") Vis(h)
printf(1,"\nDelete:\n") -- add yet a couple more items to show how F&T's original delete was -- lazier than CLRS's delete. {h} = Insert(h,"bobcat") {h} = Insert(h,"bat") printf(1,"(deleting %s)\n", {sprint(nodes[x][VALUE])}) h = Delete(h,x) Vis(h)</lang>
- Output:
MakeHeap: <empty> Insert: └── "cat" Union: ├── "cat" └── "rat" Minimum: "cat" ExtractMin: (extracted "bat") ├─┐ "cat" │ └── "rat" └── "meerkat" DecreaseKey: ├─┐ "cat" │ └── "rat" └── "gnat" Delete: (deleting "gnat") ├── "bat" ├── "bobcat" └─┐ "cat" └── "rat"
Python
<lang python>class FibonacciHeap:
# internal node class class Node: def __init__(self, data): self.data = data self.parent = self.child = self.left = self.right = None self.degree = 0 self.mark = False # function to iterate through a doubly linked list def iterate(self, head): node = stop = head flag = False while True: if node == stop and flag is True: break elif node == stop: flag = True yield node node = node.right # pointer to the head and minimum node in the root list root_list, min_node = None, None # maintain total node count in full fibonacci heap total_nodes = 0 # return min node in O(1) time def find_min(self): return self.min_node # extract (delete) the min node from the heap in O(log n) time # amortized cost analysis can be found here (http://bit.ly/1ow1Clm) def extract_min(self): z = self.min_node if z is not None: if z.child is not None: # attach child nodes to root list children = [x for x in self.iterate(z.child)] for i in xrange(0, len(children)): self.merge_with_root_list(children[i]) children[i].parent = None self.remove_from_root_list(z) # set new min node in heap if z == z.right: self.min_node = self.root_list = None else: self.min_node = z.right self.consolidate() self.total_nodes -= 1 return z # insert new node into the unordered root list in O(1) time def insert(self, data): n = self.Node(data) n.left = n.right = n self.merge_with_root_list(n) if self.min_node is None or n.data < self.min_node.data: self.min_node = n self.total_nodes += 1 # modify the data of some node in the heap in O(1) time def decrease_key(self, x, k): if k > x.data: return None x.data = k y = x.parent if y is not None and x.data < y.data: self.cut(x, y) self.cascading_cut(y) if x.data < self.min_node.data: self.min_node = x # merge two fibonacci heaps in O(1) time by concatenating the root lists # the root of the new root list becomes equal to the first list and the second # list is simply appended to the end (then the proper min node is determined) def merge(self, h2): H = FibonacciHeap() H.root_list, H.min_node = self.root_list, self.min_node # fix pointers when merging the two heaps last = h2.root_list.left h2.root_list.left = H.root_list.left H.root_list.left.right = h2.root_list H.root_list.left = last H.root_list.left.right = H.root_list # update min node if needed if h2.min_node.data < H.min_node.data: H.min_node = h2.min_node # update total nodes H.total_nodes = self.total_nodes + h2.total_nodes return H # if a child node becomes smaller than its parent node we # cut this child node off and bring it up to the root list def cut(self, x, y): self.remove_from_child_list(y, x) y.degree -= 1 self.merge_with_root_list(x) x.parent = None x.mark = False # cascading cut of parent node to obtain good time bounds def cascading_cut(self, y): z = y.parent if z is not None: if y.mark is False: y.mark = True else: self.cut(y, z) self.cascading_cut(z) # combine root nodes of equal degree to consolidate the heap # by creating a list of unordered binomial trees def consolidate(self): A = [None] * self.total_nodes nodes = [w for w in self.iterate(self.root_list)] for w in xrange(0, len(nodes)): x = nodes[w] d = x.degree while A[d] != None: y = A[d] if x.data > y.data: temp = x x, y = y, temp self.heap_link(y, x) A[d] = None d += 1 A[d] = x # find new min node - no need to reconstruct new root list below # because root list was iteratively changing as we were moving # nodes around in the above loop for i in xrange(0, len(A)): if A[i] is not None: if A[i].data < self.min_node.data: self.min_node = A[i] # actual linking of one node to another in the root list # while also updating the child linked list def heap_link(self, y, x): self.remove_from_root_list(y) y.left = y.right = y self.merge_with_child_list(x, y) x.degree += 1 y.parent = x y.mark = False # merge a node with the doubly linked root list def merge_with_root_list(self, node): if self.root_list is None: self.root_list = node else: node.right = self.root_list.right node.left = self.root_list self.root_list.right.left = node self.root_list.right = node # merge a node with the doubly linked child list of a root node def merge_with_child_list(self, parent, node): if parent.child is None: parent.child = node else: node.right = parent.child.right node.left = parent.child parent.child.right.left = node parent.child.right = node # remove a node from the doubly linked root list def remove_from_root_list(self, node): if node == self.root_list: self.root_list = node.right node.left.right = node.right node.right.left = node.left # remove a node from the doubly linked child list def remove_from_child_list(self, parent, node): if parent.child == parent.child.right: parent.child = None elif parent.child == node: parent.child = node.right node.right.parent = parent node.left.right = node.right node.right.left = node.left</lang>