/// <summary> /// Joins two heaps. O(1) /// </summary> /// <param name="h1"></param> /// <param name="h2"></param> /// <returns></returns> public static FibonacciHeap <T, TKey> Union(FibonacciHeap <T, TKey> h1, FibonacciHeap <T, TKey> h2) { var h = new FibonacciHeap <T, TKey>(h1._minKeyValue.CompareTo(h2._minKeyValue) < 0 ? h1._minKeyValue : h2._minKeyValue); if ((h1 != null) && (h2 != null)) { h._minNode = h1._minNode; if (h._minNode != null) { if (h2._minNode != null) { h._minNode.Right.Left = h2._minNode.Left; h2._minNode.Left.Right = h._minNode.Right; h._minNode.Right = h2._minNode; h2._minNode.Left = h._minNode; if (h2._minNode.Key.CompareTo(h1._minNode.Key) < 0) { h._minNode = h2._minNode; } } } else { h._minNode = h2._minNode; } h._nNodes = h1._nNodes + h2._nNodes; } return(h); }
/// <summary> /// Executes one command from the input. /// </summary> /// <param name="command">Command to be executed.</param> private void ExecuteCommand(string command) { string[] tokens = command.Split(new char[] { ' ' }); switch (tokens[0]) { // new heap case "#": if (totalCurNodes > 0) { FinishCurrentHeap(); } totalCurNodes = int.Parse(tokens[1]); Heap = new FibonacciHeap <int, int>(); Nodes = new Node <int, int> [totalCurNodes]; Heap.Naive = naive; break; // insert case "I": int id = int.Parse(tokens[1]); var n = new Node <int, int>(id, int.Parse(tokens[2])); Heap.Insert(n); Nodes[id] = n; break; // delete minimum case "M": if (Heap.NodesCount > 0) { Nodes[Heap.Minimum.Identifier] = null; } var min = Heap.DeleteMinimum(); if (min != null) { totalMin++; AverageDeleteMinimumSteps += Heap.LastOperationSteps; if (Heap.LastOperationSteps > MaxDeleteMinimumSteps) { MaxDeleteMinimumSteps = Heap.LastOperationSteps; } } break; // decrease key case "D": var decreased = Heap.DecreaseKey(int.Parse(tokens[2]), Nodes[int.Parse(tokens[1])]); if (decreased) { totalDK++; AverageDecreaseKeySteps += Heap.LastOperationSteps; if (Heap.LastOperationSteps > MaxDecreaseKeySteps) { MaxDecreaseKeySteps = Heap.LastOperationSteps; } } break; } }
/// <summary> /// Auxiliary testing method - randomly executes 1M inserts/deletes/decreases key in a 1K nodes heap. /// </summary> public static void TestHeap() { var sequenceLength = 1000000; var n = 1000; var maxPriority = 1000; var random = new Random(0); var nodes = new Node <int, int> [n]; var heap1 = new FibonacciHeap <int, int>(); for (var i = 0; i < sequenceLength; i++) { var r = random.Next(5); if (r != 1 && r != 2) // Insert { var id = random.Next(n); var key = random.Next(maxPriority); if (nodes[id] != null) { continue; } Node <int, int> node = new Node <int, int>(id, key); heap1.Insert(node); nodes[id] = node; } else if (r == 1) // Delete min { var min1 = heap1.Minimum; if (min1 == null) { continue; } heap1.DeleteMinimum(); nodes[min1.Identifier] = null; } else if (r == 2) // Decrease { var id = random.Next(n); var key = random.Next(maxPriority); var node1 = nodes[id]; heap1.DecreaseKey(key, node1); } } }
public static Dictionary <Node, double> shortestPaths(DirectedGraph <Node> graph, Node source) { // фибоначчиевая куча которая будет хранить расстояния до узлов var pq = new FibonacciHeap <double, Node>(); // словарь для соответствия узла в куче и узла в графе var entries = new Dictionary <Node, HeapNode <double, Node> >(); // узел и итоговое расстояние до него var result = new Dictionary <Node, double>(); // добавить все узлы в фибоначчиеву кучу foreach (var node in graph) { entries.Add(node, pq.Insert(double.PositiveInfinity, node)); } pq.DecreasePriority(entries[source], 0.0); // пока куча не пуста while (pq.Count != 0) { // извлечь минимум var curr = pq.ExtractMin(); // доавить в список результатов result.Add(curr.Value, curr.Priority); // рассмотреть все исходящие ребра для минимума foreach (var arc in graph.edgesFrom(curr.Value)) { // если уже записано в результат продолжить if (result.ContainsKey(arc.Key)) { continue; } // инче прибавить пройденый путь к пути от curr до acr double pathCost = curr.Priority + arc.Value; // обновить самый короткий если текущий меньше var dest = entries[arc.Key]; if (pathCost < dest.Priority) { pq.DecreasePriority(dest, pathCost); } } } return(result); }