/// <summary> /// Initializes Graph instance. /// </summary> public Graph() { m_edges = new Edges(); m_vertices = new Vertices(); m_name = string.Empty; m_desc = string.Empty; m_approxs = new Approximations(); }
/// <summary> /// Finds an efficiently directed path between specified start and destination(goal) vertices. /// </summary> /// <param name="p_start">The specific start of the search.</param> /// <param name="p_destination">The search destination.</param> /// <returns>The directed path between the specified start and destination, null if no such path exists.</returns> /// <remarks> /// <exception cref="ArgumentNullException">Start or destination is null.</exception> /// The A* search algorithm is known due its performance and accuracy. /// <para> /// https://en.wikipedia.org/wiki/A*_search_algorithm /// </para> /// </remarks> public IPath AStar(IVertex p_start, IVertex p_destination) { SearchResultPath rv = null; IApproximations approxTable = null; SearchVertex expanding = null; //current explored vertex IVertex expandingGVertex = null; //current explored vertex of the graph(cache from object expanding) string expandingName = string.Empty; //the name of the current explored vertex(cache from object expanding) Dictionary <string, byte> visited = null; //Already visited vertices, we intersted in the key only. PriorityQueue <SearchVertex> frontier = null; Dictionary <string, SearchVertex> frontierLookup = null; //Quick search if expanded vertex is in the frontier already. SearchVertex goal = null; if (null == p_start) { throw new ArgumentNullException("p_start", "Start vertex can not be null"); } else if (null == p_destination) { throw new ArgumentNullException("p_destination", "Destination vertex can not be null"); } if (p_start.Equals(p_destination)) { goal = new SearchVertex(p_start, null, 0, 0); } else { approxTable = m_graph.Approximations; frontier = new MinPriorityQueue <SearchVertex>(m_graph.Vertices.Count); frontierLookup = new Dictionary <string, SearchVertex>(); visited = new Dictionary <string, byte>(); //Initialize the frontier with our serach start SearchVertex start = new SearchVertex(p_start, null, 0, approxTable.GetH(p_start, p_destination)); frontier.Enqueue(start); frontierLookup.Add(start.Name, start); //Let's roll ... while (!frontier.IsEmpty) { //pick the best path so far, remove the vertex from the frontier and mark it as visited. expanding = frontier.Dequeue(); expandingGVertex = expanding.GraphVertex; expandingName = expandingGVertex.Name; frontierLookup.Remove(expandingName); visited.Add(expandingName, 0); //Expand ... foreach (IEdge e in expandingGVertex.OutEdges) { IVertex neighbor = e.Target; if (null == neighbor) { continue; //Dead-end } else if (visited.ContainsKey(neighbor.Name)) { continue; //We have been here before. } string neighborName = neighbor.Name; SearchVertex discovery = new SearchVertex(neighbor, expanding, e.Weight, approxTable.GetH(neighbor, p_destination)); if (neighbor.Equals(p_destination)) { //goal!! if (null == goal) { goal = discovery; } else { if (discovery.Delta < goal.Delta) { //Better path. goal = discovery; } } continue; } if (frontierLookup.ContainsKey(neighborName)) { //Still in the frontier. SearchVertex exists = frontierLookup[neighborName]; if (discovery.Delta < exists.Delta) { frontier.Remove(exists); frontierLookup.Remove(neighborName); frontier.Enqueue(discovery); frontierLookup.Add(discovery.Name, discovery); } continue; } //Don't bother if we have found a path and it is better that what we are still exploring. if (null == goal || (null != goal && discovery.Delta < goal.Delta)) { frontier.Enqueue(discovery); frontierLookup.Add(discovery.Name, discovery); } } //foreach } //while } //start != destination if (null != goal) { rv = new SearchResultPath(goal); } return(rv); }