Skip to content

Commit 3e89eaf

Browse files
authored
Merge pull request #16 from datavis-tech/dijkstra
Implement Dikjstra's algorithm
2 parents a34eace + 9f4568b commit 3e89eaf

3 files changed

Lines changed: 121 additions & 0 deletions

File tree

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,3 +220,7 @@ See **[depthFirstSearch](#dfs)** for documentation of the arguments *sourceNodes
220220
<img src="https://cloud.githubusercontent.com/assets/68416/15298394/a7a0a66a-1bbc-11e6-9636-367bed9165fc.png">
221221
</a>
222222
</p>
223+
224+
<a name="shortest-path" href="#shortest-path">#</a> <i>graph</i>.<b>shortestPath</b>(<i>sourceNode</i>, <i>destinationNode</i>)
225+
226+
Performs [Dijkstras Algorithm](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm). Returns an array of node identifier strings. The returned array includes the nodes of the shortest path from source to destination node. Inspired by by Cormen et al. "Introduction to Algorithms" 3rd Ed. p. 658.

index.js

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ module.exports = function Graph(serialized){
1515
outdegree: outdegree,
1616
depthFirstSearch: depthFirstSearch,
1717
topologicalSort: topologicalSort,
18+
shortestPath: shortestPath,
1819
serialize: serialize,
1920
deserialize: deserialize
2021
};
@@ -194,6 +195,91 @@ module.exports = function Graph(serialized){
194195
return depthFirstSearch(sourceNodes, includeSourceNodes).reverse();
195196
}
196197

198+
// Dijkstra's Shortest Path Algorithm.
199+
// Cormen et al. "Introduction to Algorithms" 3rd Ed. p. 658
200+
// Variable and function names correspond to names in the book.
201+
function shortestPath(source, destination){
202+
203+
// Upper bounds for shortest path weights from source.
204+
var d = {};
205+
206+
// Predecessors.
207+
var p = {};
208+
209+
// Poor man's priority queue, keyed on d.
210+
var q = {};
211+
212+
function initializeSingleSource(){
213+
nodes().forEach(function (node){
214+
d[node] = Infinity;
215+
});
216+
d[source] = 0;
217+
}
218+
219+
// Adds entries in q for all nodes.
220+
function initializePriorityQueue(){
221+
nodes().forEach(function (node){
222+
q[node] = true;
223+
});
224+
}
225+
226+
// Returns true if q is empty.
227+
function priorityQueueEmpty(){
228+
return Object.keys(q).length === 0;
229+
}
230+
231+
// Linear search to extract (find and remove) min from q.
232+
function extractMin(){
233+
var min = Infinity;
234+
var minNode;
235+
Object.keys(q).forEach(function(node){
236+
if (d[node] < min) {
237+
min = d[node];
238+
minNode = node;
239+
}
240+
});
241+
delete q[minNode];
242+
return minNode;
243+
}
244+
245+
function relax(u, v){
246+
var w = getEdgeWeight(u, v);
247+
if (d[v] > d[u] + w) {
248+
d[v] = d[u] + w;
249+
p[v] = u;
250+
}
251+
}
252+
253+
function dijkstra(){
254+
initializeSingleSource();
255+
initializePriorityQueue();
256+
while(!priorityQueueEmpty()){
257+
var u = extractMin();
258+
adjacent(u).forEach(function (v){
259+
relax(u, v);
260+
});
261+
}
262+
}
263+
264+
// Assembles the shortest path by traversing the
265+
// predecessor subgraph from destination to source.
266+
function path(){
267+
var nodeList = [];
268+
var node = destination;
269+
while(p[node]){
270+
nodeList.push(node);
271+
node = p[node];
272+
}
273+
nodeList.push(source);
274+
nodeList.reverse();
275+
return nodeList;
276+
}
277+
278+
dijkstra();
279+
280+
return path();
281+
}
282+
197283
// Serializes the graph.
198284
function serialize(){
199285
var serialized = {

test.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,37 @@ describe("Graph", function() {
332332
});
333333

334334
});
335+
336+
describe("Dijkstra's Shortest Path Algorithm", function (){
337+
338+
it("Should compute shortest path on a single edge.", function (){
339+
var graph = Graph().addEdge("a", "b");
340+
assert.deepEqual(graph.shortestPath("a", "b"), ["a", "b"]);
341+
});
342+
343+
it("Should compute shortest path on two edges.", function (){
344+
var graph = Graph()
345+
.addEdge("a", "b")
346+
.addEdge("b", "c");
347+
assert.deepEqual(graph.shortestPath("a", "c"), ["a", "b", "c"]);
348+
});
349+
350+
it("Should compute shortest path on example from Cormen text (p. 659).", function (){
351+
var graph = Graph()
352+
.addEdge("s", "t", 10)
353+
.addEdge("s", "y", 5)
354+
.addEdge("t", "y", 2)
355+
.addEdge("y", "t", 3)
356+
.addEdge("t", "x", 1)
357+
.addEdge("y", "x", 9)
358+
.addEdge("y", "z", 2)
359+
.addEdge("x", "z", 4)
360+
.addEdge("z", "x", 6);
361+
assert.deepEqual(graph.shortestPath("s", "z"), ["s", "y", "z"]);
362+
assert.deepEqual(graph.shortestPath("s", "x"), ["s", "y", "t", "x"]);
363+
});
364+
365+
});
335366
});
336367

337368
function contains(arr, item){

0 commit comments

Comments
 (0)