private bool SearchAndAddKthShortestPath( SortedPath previousPath, List <SortedPath> shortestPaths, IQueue <SortedPath> shortestPathCandidates) { // Iterate over all of the nodes in the (k-1)st shortest path except for the target node // For each node (up to) one new candidate path is generated by temporarily modifying // the graph and then running Dijkstra's algorithm to find the shortest path between // the node and the target in the modified graph for (int i = 0; i < previousPath.Count; ++i) { // Spur node is retrieved from the previous k-shortest path = currently visited vertex in the previous path TVertex spurVertex = previousPath.GetVertex(i); // The sequence of nodes from the source to the spur node of the previous k-shortest path EquatableTaggedEdge <TVertex, double>[] rootPath = previousPath.GetEdges(i); foreach (SortedPath path in shortestPaths) { if (rootPath.SequenceEqual(path.GetEdges(i))) { // Remove the links that are part of the previous shortest paths which share the same root path EquatableTaggedEdge <TVertex, double> edgeToRemove = path.GetEdge(i); _edgesToRestore.Add(edgeToRemove); _graph.RemoveEdge(edgeToRemove); } } var verticesToRestore = new List <TVertex>(); foreach (EquatableTaggedEdge <TVertex, double> rootPathEdge in rootPath) { TVertex source = rootPathEdge.Source; if (!EqualityComparer <TVertex> .Default.Equals(spurVertex, source)) { verticesToRestore.Add(source); _graph.EdgeRemoved += OnGraphEdgeRemoved; _graph.RemoveVertex(source); _graph.EdgeRemoved -= OnGraphEdgeRemoved; } } SortedPath?spurPath = GetShortestPathInGraph(_graph, spurVertex, _targetVertex); if (spurPath.HasValue) { // Entire path is made up of the root path and spur path var totalPath = new SortedPath(previousPath.GetEdges(i).Concat(spurPath.Value)); // Add the potential k-shortest path to the heap if (!shortestPathCandidates.Contains(totalPath)) { shortestPathCandidates.Enqueue(totalPath); } } // Add back the edges and nodes that were removed from the graph _graph.AddVertexRange(verticesToRestore); _graph.AddEdgeRange(_edgesToRestore); _edgesToRestore.Clear(); } // Identify the candidate path with the shortest cost SortedPath?newPath = ExtractShortestPathCandidate(shortestPaths, shortestPathCandidates); if (newPath is null) { // This handles the case of there being no spur paths, or no spur paths left. // This could happen if the spur paths have already been exhausted (added to A), // or there are no spur paths at all - such as when both the source and sink vertices // lie along a "dead end". return(false); } // Add the best, non-duplicate candidate identified as the k shortest path shortestPaths.Add(newPath.Value); return(true); }