create a heap to contain edges in the graph, initially empty organized by edge weight so the smallest is in the root make sure each node has a distance field (indicating its distance from the start node) and initialize that to infinity pick your start node set its distance to zero insert all its edges into the heap while the heap isn't empty remove the next edge from the heap (i.e. the smallest currently available edge) suppose the following the edge connects nodes x and y the edge has weight w x's distance is currently set to a y's distance is currently set to b then we can update as follows if a+w < b then set y's distance to a+w and insert all of y's edges into the heap otherwise, if the graph is bidirectional if b+w < a then set x's distance to b+w and insert all of x's edges into the heapOnce the while loop completes, each node's distance is correct (with unreachable nodes still having their distance set at infinity).
To get the "infinite" value we'll use the maximum floating point value we can store. This can be done by #including <climits>, and initializing each node's distance to FLT_MAX.
Note that in the spanning tree notes we created a heap class for storing edges, so we'll reuse that here.
// EXAMPLE: using the adjacency matrix graphs // and heaps from earlier notes // compute and display the distance of each node // from a designated source node // return true if successful, false otherwise bool distances(int src) { // make sure the node exists if (!Graph[src]) return false; // initialize every node's distance to infinity for (int i = 0; i < VERTICES; i++) { if (Graph[i] != NULL) { Graph[i]->distance = FLT_MAX; } } // initialize the distance to the start node Graph[src]->distance = 0; // create a heap big enough to hold all the edges heap edgelist(get_numedges()); // add all the source node's edges to the heap for (int d = 0; d < VERTICES; d++) { if (Edges[src][d] > 0) { edgenode *e = new edgenode; if (e) { e->src = src; e->dest = d; e->weight = Edges[src][d]; edgelist.insert(e); } } } // while the heap isn't empty // remove the next (smallest) edge from the heap // if the edge gives us a new shorter path // to the destination vertex then: // update the distance to that vertex // and insert all it's vertices into the graph // (if the graph is bidirectional we could do similarly // in the other direction) edgenode *e; node *s, *d; while ((e = edgelist.remove()) != NULL) { s = Graph[e->src]; d = Graph[e->dest]; float w = e->weight; if (!s || !d) { delete e; continue; } if (d->distance > (s->distance + w)) { for (int j = 0; j < VERTICES; j++) { if (Edges[e->dest][j] > 0) { edgenode *new_e = new edgenode; if (new_e) { new_e->src = e->src; new_e->dest = j; new_e->weight = Edges[e->src][j]; edgelist.insert(new_e); } } } } delete e; } // go through the graph, displaying the distance to each node for (int i = 0; i < VERTICES; i++) { if (Graph[i] && (i != src)) { cout << src << "->" << i << " distance: "; if (Graph[i]->distance == FLT_MAX) cout << "infinite" << endl; else cout << Graph[i]->distance << endl; } } }
Here we consider two additional algorithms for computing the shortest distances between every pair of vertices in a graph.
For simplicity of explanation, we'll assume we're using an adjacency matrix representation for both approaches (though for sparse graphs better efficiency would be obtained through an adjacency list approach).
Both approaches currently only store the actual distance between the pairs of vertices, but can readily be modified to store the collection of intermediate vertices as well.
Just to ease up on complications, let's also assume that VERTICES is actually the number of vertices currently in the graph (i.e. there are no null entries in the matrix, it is just as big as it needs to be).
Let's assume the graph information is stored as follows:
// for N vertices we have an NxN matrix, // where ultimately Distance[i][j] will be used // to store the shortest distance from i to j // initially, Distance[i][j] is set to 0 when i == j, // to infinity when there is no edge from i to j, // and is set to the weight of edge(i,j) otherwise float Distance[VERTICES][VERTICES];
// ALGORITHM 1: Floyd's Algorithm // for each possible intermediate vertex, // for each possible source vertex, // for each possible destination vertex, // if the known direct distance from source to destination // is larger than the sum of the known distances from // source to intermediate and intermediate to destination // then update the distance from source to destination // using the path through the intermediate vertex for (int middle = 0; middle < VERTICES; middle++) { for (int source = 0; source < VERTICES; source++) { for (int destination = 0; destination < VERTICES; destination++) { float midpath = Distance[source][middle] + Distance[middle][destination]; if (midpath < Distance[source][destination]) Distance[source][destination] = midpath; } } } |
// ALGORITHM 2: Dijkstra's Algorithm // (actually Dijkstra's algorithm applied once for each source vertex) // for each source vertex // mark all vertices as unfinished // repeat N times // find the next unfinished vertex // closest to the source // mark the vertex as finished // (its distance from the source is now known) // for each edge leaving this vertex, // if it provides a new (shorter) way // to reach another unfinished vertex then // update the distance to that vertex // again, we assume that initially the distance matrix entries are 0, // FLT_MAX, or a positive edge-weight, based on an adjacency matrix, // and again we assume VERTICES is the actual number of vertices in the // graph - there are no null entries for (int source = 0; source < VERTICES; source++) { // mark all vertices as unfinished bool finished[VERTICES]; for (int a = 0; a < VERTICES; a++) finished[a] = false; // process n vertices, each time getting the next closest one // to the source for (int n = 0; n < VERTICES; n++) { // go through all n vertices, looking for the closest // one that is not yet finished int closest = -1; float distance = FLT_MAX; for (int j = 0; j < VERTICES; j++) { if ((finished[j] == false) && (Distance[source][j] < d)) { distance = Distance[source][j]; closest = j; } } // mark the selected vertex as finished // (the distance to this vertex is now known) finished[closest] = true; // examine each edge going out from the selected vertex // to unfinished vertices, and update the distance to // the unfinished vertex is appropriate for (int current = 0; current < VERTICES; current++) { if (finished[current] == false) { // compute the distance to the current vertex based on a path // from the course to closest then to current int intermediate = Distance[source][closest] + Distance[closest][current]; // if the path through the intermediate vertex is shorter than // the previous distance to current // then update the distance to current if (Distance[source][current] > intermediate) Distance[source][current] = intermediate; } } } } |