Esempio n. 1
0
        public static SearchResult <TNode, TEdge> SearchDijkstra <TNode, TEdge>(this SparseGraph <TNode, TEdge> graph, int source, int target = -1)
            where TNode : GraphNode
            where TEdge : GraphEdge, new()
        {
            SearchResult <TNode, TEdge> result = new SearchResult <TNode, TEdge> {
                Source = source, Target = target
            };

            // this array contains the edges that comprise the shortest path tree -
            // a directed subtree of the graph that encapsulates the best paths from
            // every node on the SPT to the source node.
            TEdge[] shortestPathTree = new TEdge[graph.NumNodes];
            // this is indexed into by node index and holds the total cost of the best
            // path found so far to the given node. For example, m_CostToThisNode[5]
            // will hold the total cost of all the edges that comprise the best path
            // to node 5, found so far in the search (if node 5 is present and has
            // been visited)
            float[] costToThisNode = new float[graph.NumNodes];
            // this is an indexed (by node) vector of 'parent' edges leading to nodes
            // connected to the SPT but that have not been added to the SPT yet. This is
            // a little like the stack or queue used in BST and DST searches.
            TEdge[] searchFrontier = new TEdge[graph.NumNodes];
            // create an indexed priority queue that sorts smallest to largest
            // (front to back).Note that the maximum number of elements the iPQ
            // may contain is N. This is because no node can be represented on the
            // queue more than once.
            SimplePriorityQueue <int> pq = new SimplePriorityQueue <int>();

            //put the source node on the queue
            pq.Enqueue(source, 0);
            //while the queue is not empty
            while (pq.Count != 0)
            {
                // get lowest cost node from the queue. Don't forget, the return value
                // is a *node index*, not the node itself. This node is the node not already
                // on the SPT that is the closest to the source node
                int nextClosestNodeindex = pq.Dequeue();
                // move this edge from the frontier to the shortest path tree
                shortestPathTree[nextClosestNodeindex] = searchFrontier[nextClosestNodeindex];
                // if the target has been found exit
                if (nextClosestNodeindex == target)
                {
                    result.Found = true;
                    int node = target;
                    result.PathToTarget.Add(node);
                    while (node != source && shortestPathTree[node] != null)
                    {
                        node = shortestPathTree[node].From;
                        result.PathToTarget.Insert(0, node);
                    }
                    return(result);
                }
                // now to relax the edges.
                // for each edge connected to the next closest node
                foreach (TEdge edge in graph.Edges(nextClosestNodeindex))
                {
                    // the total cost to the node this edge points to is the cost to the
                    // current node plus the cost of the edge connecting them.
                    float newCost = costToThisNode[nextClosestNodeindex] + (float)edge.Cost;
                    // if this edge has never been on the frontier make a note of the cost
                    // to get to the node it points to, then add the edge to the frontier
                    // and the destination node to the PQ.
                    if (searchFrontier[edge.To] == null)
                    {
                        costToThisNode[edge.To] = newCost;
                        pq.Enqueue(edge.To, newCost);
                        searchFrontier[edge.To] = edge;
                    }
                    // else test to see if the cost to reach the destination node via the
                    // current node is cheaper than the cheapest cost found so far. If
                    // this path is cheaper, we assign the new cost to the destination
                    // node, update its entry in the PQ to reflect the change and add the
                    // edge to the frontier
                    else if (newCost < costToThisNode[edge.To] &&
                             shortestPathTree[edge.To] == null)
                    {
                        costToThisNode[edge.To] = newCost;
                        //because the cost is less than it was previously, the PQ must be
                        //re-sorted to account for this.
                        pq.UpdatePriority(edge.To, newCost);
                        searchFrontier[edge.To] = edge;
                    }
                }
            }
            return(result);
        }