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 }