DijkstraShortestPaths <TVertex, TEdge>( this IWeightedDirectedGraph <TVertex, TEdge> graph, TVertex origin, IAdder <TEdge> adder, IComparer <TEdge> comparer ) { if (graph == null) { throw new ArgumentNullException(nameof(graph)); } if (origin == null) { throw new ArgumentNullException(nameof(origin)); } if (adder == null) { throw new ArgumentNullException(nameof(adder)); } if (comparer == null) { throw new ArgumentNullException(nameof(comparer)); } if (!graph.Vertices.Contains(origin)) { throw new ArgumentException(); } // Constructs a dictionary which stores the graphs which contain the shortest path from the origin to // each of the vertices that is reachable from the origin by iteratively traversing successor endpoints. var graphs = new Dictionary <TVertex, IWeightedDirectedGraph <TVertex, TEdge> >(); // Constructs a dictionary which stores the additions which represent the added edges which in turn // represent the shortest path from the origin to each of the vertices when added. var accumulations = new Dictionary <TVertex, TEdge>(); var settledVertices = new HashSet <TVertex>(); var unsettledVertices = new HashSet <TVertex> { origin }; while (unsettledVertices.Count > 0) { // Returns the unsettled vertex that is nearest to the origin by finding the shortest of all the // accumulated edges which form a path from the origin to each of the unsettled vertices. Calling // the `MinBy` method with only one unsettled vertex in the set of unsettled vertices will return // that unsettled vertex, hence it will always return the origin during the first iteration over // the unsettled vertices set, because the unsettled vertices set will only contain the origin. var nearestVertex = unsettledVertices.MinBy(vertex => accumulations[vertex], comparer); // Removes the nearest vertex from the set of unvisited vertices. unsettledVertices.Remove(nearestVertex); // Iterates over each of the successor endpoints of the nearest vertex. foreach (var endpoint in graph.SuccessorEndpoints(nearestVertex)) { // If the vertex of the endpoint is already settled, then continue to the next iteration. if (settledVertices.Contains(endpoint.Vertex)) { continue; } // If the dictionary of additions contains an addition for the nearest vertex, then add this // addition and the endpoint edge together in order to calculate a single path from the origin // to the endpoint vertex of the current iteration; otherwise, an addition for the nearest vertex // does not exist so return the endpoint edge without adding. var currentPath = accumulations.ContainsKey(nearestVertex) ? adder.Add(accumulations[nearestVertex], endpoint.Edge) : endpoint.Edge; // Returns true if the dictionary of additions contains the endpoint vertex and the current path // is less than the existing shortest path from the origin to the endpoint vertex; otherwise, // false. The existing shortest path is taken from the addition of each of the endpoints from // the origin to the endpoint vertex which represent the existing shortest path when added. bool IsCurrentPathLessThanShortestPath() { return(accumulations.ContainsKey(endpoint.Vertex) && comparer.Compare(currentPath, accumulations[endpoint.Vertex]) < 0); } // If the dictionary of graphs does not contain a graph for the endpoint vertex or the current // path is less than the existing shortest path, then update the graph of the endpoint vertex. if (!graphs.ContainsKey(endpoint.Vertex) || IsCurrentPathLessThanShortestPath()) { // If the dictionary of graphs contains a graph for the nearest vertex, then a shortest path // from the origin to the nearest vertex already exists so return a copy of this graph; // otherwise, such a shortest path does not exist so return a new empty graph. var currentGraph = graphs.ContainsKey(nearestVertex) ? graphs[nearestVertex].EndpointPairs.ToGraph() : new WeightedDirectedGraph <TVertex, TEdge>(); // Adds an edge from the nearest vertex to the vertex of the endpoint. This means that the // graph will now contain endpoint pairs from the origin to the endpoint vertex. currentGraph.AddEdge(nearestVertex, endpoint.Vertex, endpoint.Edge); // Updates the graph of the endpoint vertex with the current graph because the current graph // contains a shorter path from the origin to the endpoint vertex than the existing graph. graphs[endpoint.Vertex] = currentGraph; // Updates the addition of the endpoint vertex with the current path for the same reason. accumulations[endpoint.Vertex] = currentPath; } // Adds the endpoint vertex to the set of unsettled vertices. unsettledVertices.Add(endpoint.Vertex); } // Adds the nearest vertex to the set of settled vertices. settledVertices.Add(nearestVertex); } return(graphs); }
public static IEnumerable <IWeightedDirectedPath <TVertex, TEdge> > AllSimplePaths <TVertex, TEdge>( this IWeightedDirectedGraph <TVertex, TEdge> graph, TVertex origin, TVertex destination, IAdder <TEdge> adder, int maxDepth = int.MaxValue ) { if (graph == null) { throw new ArgumentNullException(nameof(graph)); } if (origin == null) { throw new ArgumentNullException(nameof(origin)); } if (destination == null) { throw new ArgumentNullException(nameof(destination)); } if (adder == null) { throw new ArgumentNullException(nameof(adder)); } if (!graph.Vertices.Contains(origin)) { throw new ArgumentException(); } if (!graph.Vertices.Contains(destination)) { throw new ArgumentException(); } var visitedVertices = new Stack <TVertex>(); var visitedEdges = new Stack <TEdge>(); var paths = new HashSet <IWeightedDirectedPath <TVertex, TEdge> >(); visitedVertices.Push(origin); var stack = new Stack <Tuple <TVertex, Queue <IWeightedEndpoint <TVertex, TEdge> > > >(); stack.Push(new Tuple <TVertex, Queue <IWeightedEndpoint <TVertex, TEdge> > >( origin, graph.SuccessorEndpoints(origin).ToQueue() )); while (stack.Count > 0) { var(vertex, successorEndpoints) = stack.Peek(); if (Equals(vertex, destination) || successorEndpoints.Count == 0 || stack.Count > maxDepth) { if (Equals(vertex, destination)) { var weightedDirectedPath = new WeightedDirectedPath <TVertex, TEdge>( graph, origin, destination, new Stack <TVertex>(visitedVertices), new Stack <TEdge>(visitedEdges), visitedEdges.Aggregate(adder.Add) ); paths.Add(weightedDirectedPath); } if (visitedVertices.Count > 0) { visitedVertices.Pop(); } if (visitedEdges.Count > 0) { visitedEdges.Pop(); } stack.Pop(); } else { var successorEndpoint = successorEndpoints.Dequeue(); visitedVertices.Push(successorEndpoint.Vertex); visitedEdges.Push(successorEndpoint.Edge); bool Predicate(IWeightedEndpoint <TVertex, TEdge> grandchildEndpoint) { return(!visitedVertices.Contains(grandchildEndpoint.Vertex)); } stack.Push(new Tuple <TVertex, Queue <IWeightedEndpoint <TVertex, TEdge> > >( successorEndpoint.Vertex, graph.SuccessorEndpoints(successorEndpoint.Vertex).Where(Predicate).ToQueue() )); } } return(paths); }