/// <summary> /// Uses Kruskal's algorithm to build an MST spanning the mstNodes /// with the given edges as a list ordered by priority ascending. /// The edges don't need to contain only nodes given to this instance /// via constructor. /// O(|edges|) runtime. /// </summary> /// <param name="ordererdEdges">Edges ordered by priority ascending.</param> /// <remarks> /// Both Span methods have quadratic runtime in the graph nodes. This one /// has a lower constant factor but needs to filter out unneeded edges (quadratic /// in all nodes), the other one doesn't need to do any filtering (quadratic in /// considered nodes) so if the mst nodes are generally only a very small /// portion of all nodes, use the other Span method, if not, use this one. /// </remarks> public void Span(IEnumerable <DirectedGraphEdge> ordererdEdges) { var mstEdges = new List <DirectedGraphEdge>(_mstNodes.Count); var set = new DisjointSet(_distances.CacheSize); var considered = new bool[_distances.CacheSize]; var toAddCount = _mstNodes.Count - 1; foreach (var t in _mstNodes) { considered[t] = true; } foreach (var current in ordererdEdges) { var inside = current.Inside; var outside = current.Outside; // This condition is by far the bottleneck of the method. // (most likely because branch prediction can't predict the result) if (!considered[inside] | !considered[outside]) { continue; } if (set.Find(inside) == set.Find(outside)) { continue; } mstEdges.Add(current); set.Union(inside, outside); if (--toAddCount == 0) { break; } } SpanningEdges = mstEdges; }
/// <summary> /// Uses Kruskal's algorithm to build an MST spanning the mstNodes /// with the given edges as a linked list ordered by priority ascending. /// The edges don't need to contain only nodes given to this instance /// via constructor. /// O(|edges|) runtime. /// </summary> /// <param name="first">First edge of the linked list.</param> /// <remarks> /// Both Span methods have quadratic runtime in the graph nodes. This one /// has a lower constant factor but needs to filter out unneeded edges (quadratic /// in all nodes), the other one doesn't need to do any filtering (quadratic in /// considered nodes) so if the mst nodes are generally only a very small /// portion of all nodes, use the other Span method, if not, use this one. /// </remarks> public void Span(LinkedGraphEdge first) { var mstEdges = new List <GraphEdge>(_mstNodes.Count); var set = new DisjointSet(_distances.CacheSize); var considered = new bool[_distances.CacheSize]; var toAddCount = _mstNodes.Count - 1; foreach (var t in _mstNodes) { considered[t.DistancesIndex] = true; } for (var current = first; current != null; current = current.Next) { var inside = current.Inside; var outside = current.Outside; // This condition is by far the bottleneck of the method. // (most likely because branch prediction can't predict the result) if (!considered[inside] | !considered[outside]) { continue; } if (set.Find(inside) == set.Find(outside)) { continue; } mstEdges.Add(new GraphEdge(_distances.IndexToNode(inside), _distances.IndexToNode(outside))); set.Union(inside, outside); if (--toAddCount == 0) { break; } } SpanningEdges = mstEdges; IsSpanned = true; }
/// <summary> /// Uses Kruskal's algorithm to build an MST spanning the mstNodes /// with the given edges as a list ordered by priority ascending. /// The edges don't need to contain only nodes given to this instance /// via constructor. /// O(|edges|) runtime. /// </summary> /// <param name="ordererdEdges">Edges ordered by priority ascending.</param> /// <remarks> /// Both Span methods have quadratic runtime in the graph nodes. This one /// has a lower constant factor but needs to filter out unneeded edges (quadratic /// in all nodes), the other one doesn't need to do any filtering (quadratic in /// considered nodes) so if the mst nodes are generally only a very small /// portion of all nodes, use the other Span method, if not, use this one. /// </remarks> public void Span(IEnumerable<DirectedGraphEdge> ordererdEdges) { var mstEdges = new List<DirectedGraphEdge>(_mstNodes.Count); var set = new DisjointSet(_distances.CacheSize); var considered = new bool[_distances.CacheSize]; var toAddCount = _mstNodes.Count - 1; foreach (var t in _mstNodes) { considered[t] = true; } foreach (var current in ordererdEdges) { var inside = current.Inside; var outside = current.Outside; // This condition is by far the bottleneck of the method. // (most likely because branch prediction can't predict the result) if (!considered[inside] | !considered[outside]) continue; if (set.Find(inside) == set.Find(outside)) continue; mstEdges.Add(current); set.Union(inside, outside); if (--toAddCount == 0) break; } SpanningEdges = mstEdges; }