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