Skip to content

Commit

Permalink
Merge pull request #16 from datavis-tech/dijkstra
Browse files Browse the repository at this point in the history
Implement Dikjstra's algorithm
  • Loading branch information
curran authored Mar 9, 2018
2 parents a34eace + 9f4568b commit 3e89eaf
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 0 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -220,3 +220,7 @@ See **[depthFirstSearch](#dfs)** for documentation of the arguments *sourceNodes
<img src="https://cloud.githubusercontent.com/assets/68416/15298394/a7a0a66a-1bbc-11e6-9636-367bed9165fc.png">
</a>
</p>

<a name="shortest-path" href="#shortest-path">#</a> <i>graph</i>.<b>shortestPath</b>(<i>sourceNode</i>, <i>destinationNode</i>)

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.
86 changes: 86 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ module.exports = function Graph(serialized){
outdegree: outdegree,
depthFirstSearch: depthFirstSearch,
topologicalSort: topologicalSort,
shortestPath: shortestPath,
serialize: serialize,
deserialize: deserialize
};
Expand Down Expand Up @@ -194,6 +195,91 @@ module.exports = function Graph(serialized){
return depthFirstSearch(sourceNodes, includeSourceNodes).reverse();
}

// Dijkstra's Shortest Path Algorithm.
// Cormen et al. "Introduction to Algorithms" 3rd Ed. p. 658
// Variable and function names correspond to names in the book.
function shortestPath(source, destination){

// Upper bounds for shortest path weights from source.
var d = {};

// Predecessors.
var p = {};

// Poor man's priority queue, keyed on d.
var q = {};

function initializeSingleSource(){
nodes().forEach(function (node){
d[node] = Infinity;
});
d[source] = 0;
}

// Adds entries in q for all nodes.
function initializePriorityQueue(){
nodes().forEach(function (node){
q[node] = true;
});
}

// Returns true if q is empty.
function priorityQueueEmpty(){
return Object.keys(q).length === 0;
}

// Linear search to extract (find and remove) min from q.
function extractMin(){
var min = Infinity;
var minNode;
Object.keys(q).forEach(function(node){
if (d[node] < min) {
min = d[node];
minNode = node;
}
});
delete q[minNode];
return minNode;
}

function relax(u, v){
var w = getEdgeWeight(u, v);
if (d[v] > d[u] + w) {
d[v] = d[u] + w;
p[v] = u;
}
}

function dijkstra(){
initializeSingleSource();
initializePriorityQueue();
while(!priorityQueueEmpty()){
var u = extractMin();
adjacent(u).forEach(function (v){
relax(u, v);
});
}
}

// Assembles the shortest path by traversing the
// predecessor subgraph from destination to source.
function path(){
var nodeList = [];
var node = destination;
while(p[node]){
nodeList.push(node);
node = p[node];
}
nodeList.push(source);
nodeList.reverse();
return nodeList;
}

dijkstra();

return path();
}

// Serializes the graph.
function serialize(){
var serialized = {
Expand Down
31 changes: 31 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,37 @@ describe("Graph", function() {
});

});

describe("Dijkstra's Shortest Path Algorithm", function (){

it("Should compute shortest path on a single edge.", function (){
var graph = Graph().addEdge("a", "b");
assert.deepEqual(graph.shortestPath("a", "b"), ["a", "b"]);
});

it("Should compute shortest path on two edges.", function (){
var graph = Graph()
.addEdge("a", "b")
.addEdge("b", "c");
assert.deepEqual(graph.shortestPath("a", "c"), ["a", "b", "c"]);
});

it("Should compute shortest path on example from Cormen text (p. 659).", function (){
var graph = Graph()
.addEdge("s", "t", 10)
.addEdge("s", "y", 5)
.addEdge("t", "y", 2)
.addEdge("y", "t", 3)
.addEdge("t", "x", 1)
.addEdge("y", "x", 9)
.addEdge("y", "z", 2)
.addEdge("x", "z", 4)
.addEdge("z", "x", 6);
assert.deepEqual(graph.shortestPath("s", "z"), ["s", "y", "z"]);
assert.deepEqual(graph.shortestPath("s", "x"), ["s", "y", "t", "x"]);
});

});
});

function contains(arr, item){
Expand Down

0 comments on commit 3e89eaf

Please sign in to comment.