namespace System.Collections.Generic;
///
/// Fibonacci Heap implementation.
///
/// Provided type
[Serializable]
public sealed class FibonacciHeap : IEnumerable where T : IComparable
{
#region Fields
private FibonacciNode root = default!;
private int count;
#endregion
#region Properties
///
/// Count of values in the heap.
///
public int Count
{
get
{
return this.count;
}
}
///
/// Minimal value contained in the heap.
///
public T Minimum
{
get
{
return this.root.Value;
}
}
#endregion
#region Constructors
///
/// Constructor for Fibonacci heap data structure.
///
public FibonacciHeap()
{
}
#endregion
#region Public Methods
///
/// Adds value to the heap.
///
/// Value to be added.
public void Add(T value)
{
var node = new FibonacciNode
{
Value = value,
Marked = false,
Child = default!,
Parent = default!,
Degree = 0
};
node.Previous = node.Next = node;
this.root = this.Merge(this.root, node);
this.count++;
}
///
/// Merge current heap with another heap. The other heap will be disposed at the end of this method.
///
/// The heap to be merged with the current heap.
public void Merge(FibonacciHeap otherHeap)
{
this.root = this.Merge(this.root, otherHeap.root);
otherHeap.root = default!;
this.count += otherHeap.count;
}
///
/// Remove the minimum value from the heap.
///
/// Minimum value.
public T Remove()
{
var currentRoot = this.root;
if (currentRoot != null)
{
this.root = this.RemoveMinimum(this.root)!;
this.count--;
return currentRoot.Value;
}
else
{
throw new IndexOutOfRangeException("Heap is empty!");
}
}
///
/// Decrease the old value to a new provided value.
///
/// Old value used to find the node to have its key decreased.
/// New value to be assigned to the node.
public void DecreaseKey(T oldValue, T value)
{
var node = this.Find(this.root, oldValue);
this.root = this.DecreaseKey(this.root, node, value);
}
///
/// Determines whether the heap contains a specified value.
///
/// Value to locate in the heap.
///
public bool Contains(T value)
{
return this.Find(this.root, value) != null;
}
///
/// Clears the heap.
///
public void Clear()
{
this.count = 0;
this.Remove(this.root);
this.root.Next = this.root.Previous = this.root.Parent = this.root.Child = default!;
this.root = default!;
}
///
/// Return the heap structure as an array. Array is not sorted other than the
/// actual structure of the heap.
///
/// Array with values from the heap.
public T[] ToArray()
{
if (this.count == 0)
{
return default!;
}
var array = new T[this.count];
if (this.count == 1)
{
array[0] = this.root.Value;
return array;
}
else
{
var index = 0;
this.RecursiveFillArray(this.root, ref array, ref index);
return array;
}
}
///
/// Enumerator that iterates over the heap. Note that the values are not sorted in any way.
///
/// Enumerator that iterates over the heap.
public IEnumerator GetEnumerator()
{
return this.GetEnumerator(this.root);
}
#endregion
#region Private Methods
///
/// Recursively traverse the heap and copy its contents to an array.
///
/// Current node.
/// Array to be filled with contents of heap.
/// Index of the next unintialized element in the array.
private void RecursiveFillArray(FibonacciNode currentNode, ref T[] array, ref int index)
{
var oldNode = currentNode;
do
{
array[index] = currentNode.Value;
index++;
if (currentNode.HasChildren())
{
this.RecursiveFillArray(currentNode.Child, ref array, ref index);
}
currentNode = currentNode.Previous;
} while (currentNode != oldNode);
}
///
/// Recursively enumerates over the tree.
///
/// Current node in the iteration.
private IEnumerator GetEnumerator(FibonacciNode currentNode)
{
var queue = new Queue>();
queue.Enqueue(currentNode);
while (queue.Count > 0)
{
currentNode = queue.Dequeue();
var oldNode = currentNode;
do
{
yield return currentNode.Value;
if (currentNode.HasChildren())
{
queue.Enqueue(currentNode.Child);
}
currentNode = currentNode.Previous;
} while (currentNode != oldNode);
}
}
///
/// Recursively remove the node and its children from the heap.
///
/// Node to be removed.
private void Remove(FibonacciNode node)
{
if (node != null)
{
var current = node;
do
{
this.Remove(current.Child);
if (current.Parent != null)
{
current.Parent.Child = default!;
}
current = current.Next;
} while (current != node);
current.Next = current.Previous = current.Child = current.Parent = default!;
}
}
///
/// Merge two heaps into a larger heap.
///
/// Root of first heap.
/// Root of second heap.
private FibonacciNode Merge(FibonacciNode node1, FibonacciNode node2)
{
if (node1 == null)
{
return node2;
}
if (node2 == null)
{
return node1;
}
if (node1.Value.CompareTo(node2.Value) > 0)
{
var temp = node1;
node1 = node2;
node2 = temp;
}
var node1Next = node1.Next;
var node2Prev = node2.Previous;
node1.Next = node2;
node2.Previous = node1;
node1Next.Previous = node2Prev;
node2Prev.Next = node1Next;
return node1;
}
///
/// Adds child to the parent.
///
/// Parent node to accept child.
/// Child node to be added to the parent.
private void AddChild(FibonacciNode parent, FibonacciNode child)
{
child.Previous = child.Next = child;
child.Parent = parent;
parent.Degree++;
parent.Child = this.Merge(parent.Child, child);
}
///
/// Removes the parent of the specified node.
///
/// Node to be removed from its parent.
private void RemoveParent(FibonacciNode node)
{
if (node == null)
{
return;
}
var current = node;
do
{
current.Marked = false;
current.Parent = default!;
current = current.Next;
} while (current != node);
}
///
/// Removes the minimum node from the provided tree.
///
/// Root of the provided tree.
///
private FibonacciNode? RemoveMinimum(FibonacciNode node)
{
this.RemoveParent(node.Child);
if (node.Next == node)
{
node = node.Child;
}
else
{
node.Next.Previous = node.Previous;
node.Previous.Next = node.Next;
node = this.Merge(node.Next, node.Child);
}
if (node == null)
{
return node;
}
var trees = new FibonacciNode[64];
while (true)
{
if (trees[node.Degree] != null)
{
var t = trees[node.Degree];
if (t == node)
{
break;
}
trees[node.Degree] = default!;
if (node.Value.CompareTo(t.Value) < 0)
{
t.Previous.Next = t.Next;
t.Next.Previous = t.Previous;
this.AddChild(node, t);
}
else
{
t.Previous.Next = t.Next;
t.Next.Previous = t.Previous;
if (node.Next == node)
{
t.Next = t.Previous = t;
this.AddChild(t, node);
node = t;
}
else
{
node.Previous.Next = t;
node.Next.Previous = t;
t.Next = node.Next;
t.Previous = node.Previous;
this.AddChild(t, node);
node = t;
}
}
continue;
}
else
{
trees[node.Degree] = node;
}
node = node.Next;
}
var min = node;
var start = node;
do
{
if (node.Value.CompareTo(min.Value) < 0)
{
min = node;
}
node = node.Next;
} while (node != start);
return min;
}
///
/// Cut node from heap.
///
/// Root of heap.
/// Node to be cut.
///
private FibonacciNode Cut(FibonacciNode root, FibonacciNode node)
{
if (node.Next == node)
{
node.Parent.Child = default!;
}
else
{
node.Next.Previous = node.Previous;
node.Previous.Next = node.Next;
node.Parent.Child = node.Next;
}
node.Next = node.Previous = node;
node.Marked = false;
return this.Merge(root, node);
}
///
/// Decrease value of provided node substituting it with the provided value.
///
/// Root of the heap.
/// Node to have value decreased.
/// New value of the node. It is only applied if the value is lower than the previous value.
///
private FibonacciNode DecreaseKey(FibonacciNode root, FibonacciNode node, T value)
{
if (node.Value.CompareTo(value) < 0)
{
return root;
}
node.Value = value;
if (node.Parent != null)
{
if (node.Value.CompareTo(node.Parent.Value) < 0)
{
root = this.Cut(root, node);
var parent = node.Parent;
node.Parent = default!;
while (parent != null && parent.Marked)
{
root = this.Cut(root, parent);
node = parent;
parent = node.Parent;
node.Parent = default!;
}
if (parent != null && parent.Parent != null)
{
parent.Marked = true;
}
}
}
else
{
if (node.Value.CompareTo(root.Value) < 0)
{
root = node;
}
}
return root;
}
///
/// Find the node that has the specified value in the heap.
///
/// Root of the heap.
/// Value to be found.
///
private FibonacciNode Find(FibonacciNode root, T value)
{
var node = root;
if (node == null)
{
return default!;
}
do
{
if (node.Value.CompareTo(value) == 0)
{
return node;
}
var ret = this.Find(node.Child, value);
if (ret != null)
{
return ret;
}
node = node.Next;
} while (node != root);
return default!;
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
#endregion
}
[Serializable]
internal sealed class FibonacciNode
{
#region Fields
private FibonacciNode previous = default!;
private FibonacciNode next = default!;
private FibonacciNode child = default!;
private FibonacciNode parent = default!;
private T value = default!;
private int degree;
private bool marked;
#endregion
#region Properties
public FibonacciNode Previous
{
get
{
return this.previous;
}
set
{
this.previous = value;
}
}
public FibonacciNode Next
{
get
{
return this.next;
}
set
{
this.next = value;
}
}
public FibonacciNode Child
{
get
{
return this.child;
}
set
{
this.child = value;
}
}
public FibonacciNode Parent
{
get
{
return this.parent;
}
set
{
this.parent = value;
}
}
public bool Marked
{
get
{
return this.marked;
}
set
{
this.marked = value;
}
}
public T Value
{
get
{
return this.value;
}
set
{
this.value = value;
}
}
public int Degree
{
get
{
return this.degree;
}
set
{
this.degree = value;
}
}
#endregion
#region Public Methods
public bool HasChildren()
{
return this.child != null;
}
public bool HasParent()
{
return this.parent != null;
}
#endregion
}