/// <summary> /// Finds the shortest path with specified start and end using breath first search. /// </summary> /// <typeparam name="TNode">The value contained in the node.</typeparam> /// <param name="start">The start node.</param> /// <param name="end">The end node.</param> public static IEnumerable <Node <TNode> > FindShortestPath <TNode>(Node <TNode> start, Node <TNode> end) { var frontier = new Queue <Node <TNode> >(); frontier.Enqueue(start); var visitedNodes = new NodeDictionary <TNode>(); visitedNodes.Add(start); while (frontier.Count > 0) { var currentNode = frontier.Dequeue(); if (currentNode.Equals(end)) { break; } foreach (var edge in currentNode.Edges) { if (!visitedNodes.Contains(edge.Target)) { frontier.Enqueue(edge.Target); visitedNodes.Add(edge.Target, currentNode); } } } var path = BacktrackPathTo(end, visitedNodes); return(path); }
/// <summary> /// Finds the cheapest path with specified start and end using the Dijkstra algorithm (AKA Uniform Cost Search). /// </summary> /// <typeparam name="TNode">The value contained in the node.</typeparam> /// <param name="start">The start node.</param> /// <param name="end">The end node.</param> /// <param name="graph">The graph to operate on.</param> public static IEnumerable <Node <TNode> > FindCheapestPath <TNode>(Node <TNode> start, Node <TNode> end, UndirectedGraph <TNode> graph) { var frontier = new Queue <Node <TNode> >(); frontier.Enqueue(start); var visitedNodes = new NodeDictionary <TNode>(); visitedNodes.Add(start); var costs = InitializeCosts(graph); costs[start] = 0d; while (frontier.Count > 0) { var currentNode = frontier.Dequeue(); if (currentNode.Equals(end)) { break; } var prioritizedEdges = new PriorityQueue <Edge <TNode> >(currentNode.Edges); while (prioritizedEdges.Count > 0) { var edge = prioritizedEdges.Dequeue(); var currentCost = costs[edge.Target]; var newCost = costs[currentNode] + edge.Weight; if (newCost < currentCost) { costs[edge.Target] = newCost; // A cheaper path is found, so the target node predecesor must be replaced with the current node. if (visitedNodes.Contains(edge.Target)) { visitedNodes[edge.Target] = currentNode; } } if (!visitedNodes.Contains(edge.Target)) { frontier.Enqueue(edge.Target); visitedNodes.Add(edge.Target, currentNode); } } } var path = BacktrackPathTo(end, visitedNodes); return(path); }
private static IEnumerable <Node <TNode> > BacktrackPathTo <TNode>(Node <TNode> end, NodeDictionary <TNode> visitedNodes) { LinkedList <Node <TNode> > path = new LinkedList <Node <TNode> >(); Node <TNode> current = end; Node <TNode> previous = null; if (visitedNodes.Contains(end)) { current = end; previous = visitedNodes.GetPrevious(current); } while (previous != null) { path.AddFirst(current); current = previous; previous = visitedNodes.GetPrevious(current); } path.AddFirst(current); return(path); }