/// <summary> /// Uses Prim's algorithm to build an MST spanning the mstNodes. /// O(|mstNodes|^2) runtime. /// </summary> /// <param name="startIndex">The node index to start from.</param> public void Span(int startIndex) { // All nodes that are not yet included. var toAdd = new List <int>(_mstNodes.Count); // If the index node is already included. var inMst = new bool[_distances.CacheSize]; // The spanning edges. var mstEdges = new List <DirectedGraphEdge>(_mstNodes.Count); using (var adjacentEdgeQueue = new LinkedListPriorityQueue <DirectedGraphEdge>(100, _mstNodes.Count * _mstNodes.Count)) { foreach (var t in _mstNodes) { if (t != startIndex) { toAdd.Add(t); adjacentEdgeQueue.Enqueue(new DirectedGraphEdge(startIndex, t), _distances[startIndex, t]); } } inMst[startIndex] = true; while (toAdd.Count > 0 && !adjacentEdgeQueue.IsEmpty) { int newIn; DirectedGraphEdge shortestEdge; // Dequeue and ignore edges that are already inside the MST. // Add the first one that is not. do { shortestEdge = adjacentEdgeQueue.Dequeue(); newIn = shortestEdge.Outside; } while (inMst[newIn]); mstEdges.Add(shortestEdge); inMst[newIn] = true; // Find all newly adjacent edges and enqueue them. for (var i = 0; i < toAdd.Count; i++) { var otherNode = toAdd[i]; if (otherNode == newIn) { toAdd.RemoveAt(i--); } else { adjacentEdgeQueue.Enqueue(new DirectedGraphEdge(newIn, otherNode), _distances[newIn, otherNode]); } } } } SpanningEdges = mstEdges; }
private void InitializeDataStructures( int startIndex, int[] notIncluded, ref int notIncludedCount, LinkedListPriorityQueue <DirectedGraphEdge> adjacentEdgeQueue) { for (var i = 0; i < _mstNodes.Count; i++) { var t = _mstNodes[i]; if (t != startIndex) { notIncluded[notIncludedCount] = t; notIncludedCount++; var distance = _distances[startIndex, t]; adjacentEdgeQueue.Enqueue(new DirectedGraphEdge(startIndex, t), distance); } } }
public void Test() { int[] queueTestOrder = { 10, 3, 11, 6, -3, 17, 13, -6, 2, 8, -2, -8 }; var queue = new LinkedListPriorityQueue <TestNode>(30, queueTestOrder.Length); foreach (int t in queueTestOrder) { if (t > 0) { queue.Enqueue(new TestNode(t), (uint)t); } if (t < 0) { Assert.IsTrue(queue.Dequeue().Priority == -t); } } }
/// <summary> /// Uses Prim's algorithm to build an MST spanning the mstNodes. /// O(|mstNodes|^2) runtime. /// </summary> /// <param name="startIndex">The node index to start from.</param> public IReadOnlyList <DirectedGraphEdge> Span(int startIndex) { var notIncluded = ArrayPool <int> .Shared.Rent(_mstNodes.Count); var notIncludedCount = 0; var isIncluded = ArrayPool <bool> .Shared.Rent(_distances.CacheSize); Array.Clear(isIncluded, 0, isIncluded.Length); _spanningEdges?.Dispose(); _spanningEdges = new PooledList <DirectedGraphEdge>(_mstNodes.Count); using (var adjacentEdgeQueue = new LinkedListPriorityQueue <DirectedGraphEdge>(100, _mstNodes.Count * _mstNodes.Count)) { InitializeDataStructures(startIndex, notIncluded, ref notIncludedCount, adjacentEdgeQueue); isIncluded[startIndex] = true; while (notIncludedCount > 0 && !adjacentEdgeQueue.IsEmpty) { int newIn; DirectedGraphEdge shortestEdge; // Dequeue and ignore edges that are already inside the MST. // Add the first one that is not. do { shortestEdge = adjacentEdgeQueue.Dequeue(); newIn = shortestEdge.Outside; } while (isIncluded[newIn]); _spanningEdges.Add(shortestEdge); isIncluded[newIn] = true; // Find all newly adjacent edges and enqueue them. IncludeNode(notIncluded, ref notIncludedCount, adjacentEdgeQueue, newIn); } } ArrayPool <bool> .Shared.Return(isIncluded); ArrayPool <int> .Shared.Return(notIncluded); return(_spanningEdges); }
private void IncludeNode( int[] notIncluded, ref int notIncludedCount, LinkedListPriorityQueue <DirectedGraphEdge> adjacentEdgeQueue, int node) { for (var i = 0; i < notIncludedCount; i++) { var otherNode = notIncluded[i]; if (otherNode == node) { RemoveAt(notIncluded, ref notIncludedCount, i); i--; } else { var distance = _distances[node, otherNode]; adjacentEdgeQueue.Enqueue(new DirectedGraphEdge(node, otherNode), distance); } } }