using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace SystemExtensions.Collections { /// /// Fibonacci Heap implementation. /// /// Provided type public class FibonacciHeap { #region Fields private FibonacciNode root; private Comparison comparator; private int count; #endregion #region Properties /// /// Count of values in the heap. /// public int Count { get { return count; } } /// /// Minimal value contained in the heap. /// public T Minimum { get { return root.Value; } } #endregion #region Constructors /// /// Constructor for Fibonacci heap data structure. /// /// Function used to compare the elements. public FibonacciHeap(Comparison comparator) { this.comparator = comparator; } #endregion #region Public Methods /// /// Inserts value into the heap. /// /// Value to be inserted. public void Insert(T value) { FibonacciNode node = new FibonacciNode(); node.Value = value; node.Previous = node.Next = node; node.Degree = 0; node.Marked = false; node.Child = null; node.Parent = null; root = Merge(root, node); 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) { root = Merge(root, otherHeap.root); otherHeap.root = null; count += otherHeap.count; } /// /// Remove the minimum value from the heap. /// /// Minimum value. public T RemoveMinimum() { FibonacciNode currentRoot = root; if (currentRoot != null) { root = RemoveMinimum(root); 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) { FibonacciNode node = Find(root, oldValue); root = DecreaseKey(root, node, value); } /// /// Determines whether the heap contains a specified value. /// /// Value to locate in the heap. /// public bool Contains(T value) { return Find(root, value) != null; } /// /// Clears the heap. /// public void Clear() { count = 0; Remove(root); root.Next = root.Previous = root.Parent = root.Child = null; root = null; } /// /// 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(count == 0) { return null; } T[] array = new T[count]; if (count == 1) { array[0] = root.Value; return array; } else { int index = 0; RecursiveFillArray(root, ref array, ref index); return array; } } #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) { FibonacciNode oldNode = currentNode; do { array[index] = currentNode.Value; index++; if (currentNode.HasChildren()) { RecursiveFillArray(currentNode.Child, ref array, ref index); } 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) { FibonacciNode current = node; do { Remove(current.Child); if (current.Parent != null) { current.Parent.Child = null; } current = current.Next; } while (current != node); current.Next = current.Previous = current.Child = current.Parent = null; } } /// /// 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(comparator(node1.Value, node2.Value) > 0) { FibonacciNode temp = node1; node1 = node2; node2 = temp; } FibonacciNode node1Next = node1.Next; FibonacciNode 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 = 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; } FibonacciNode current = node; do { current.Marked = false; current.Parent = null; current = current.Next; } while (current != node); } /// /// Removes the minimum node from the provided tree. /// /// Root of the provided tree. /// private FibonacciNode RemoveMinimum(FibonacciNode node) { RemoveParent(node.Child); if(node.Next == node) { node = node.Child; } else { node.Next.Previous = node.Previous; node.Previous.Next = node.Next; node = Merge(node.Next, node.Child); } if(node == null) { return node; } FibonacciNode[] trees = new FibonacciNode[64]; while (true) { if(trees[node.Degree] != null) { FibonacciNode t = trees[node.Degree]; if(t == node) { break; } trees[node.Degree] = null; if(comparator(node.Value, t.Value) < 0) { t.Previous.Next = t.Next; t.Next.Previous = t.Previous; AddChild(node, t); } else { t.Previous.Next = t.Next; t.Next.Previous = t.Previous; if(node.Next == node) { t.Next = t.Previous = t; AddChild(t, node); node = t; } else { node.Previous.Next = t; node.Next.Previous = t; t.Next = node.Next; t.Previous = node.Previous; AddChild(t, node); node = t; } } continue; } else { trees[node.Degree] = node; } node = node.Next; } FibonacciNode min = node; FibonacciNode start = node; do { if(comparator(node.Value, 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 = null; } 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 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(comparator(node.Value, value) < 0) { return root; } node.Value = value; if(node.Parent != null) { if(comparator(node.Value, node.Parent.Value) < 0) { root = Cut(root, node); FibonacciNode parent = node.Parent; node.Parent = null; while(parent != null && parent.Marked) { root = Cut(root, parent); node = parent; parent = node.Parent; node.Parent = null; } if(parent != null && parent.Parent != null) { parent.Marked = true; } } } else { if(comparator(node.Value, 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) { FibonacciNode node = root; if(node == null) { return null; } do { if(comparator(node.Value, value) == 0) { return node; } FibonacciNode ret = Find(node.Child, value); if(ret != null) { return ret; } node = node.Next; } while (node != root); return null; } #endregion } internal class FibonacciNode { #region Fields private FibonacciNode previous; private FibonacciNode next; private FibonacciNode child; private FibonacciNode parent; private T value; private int degree; private bool marked; #endregion #region Properties public FibonacciNode Previous { get { return previous; } set { previous = value; } } public FibonacciNode Next { get { return next; } set { next = value; } } public FibonacciNode Child { get { return child; } set { child = value; } } public FibonacciNode Parent { get { return parent; } set { parent = value; } } public bool Marked { get { return marked; } set { marked = value; } } public T Value { get { return value; } set { this.value = value; } } public int Degree { get { return degree; } set { degree = value; } } #endregion #region Public Methods public bool HasChildren() { return child != null; } public bool HasParent() { return parent != null; } #endregion } }