Skip to content

Commit

Permalink
Merge 60dae77 into 5c6a696
Browse files Browse the repository at this point in the history
  • Loading branch information
tayllan committed Jun 2, 2014
2 parents 5c6a696 + 60dae77 commit ebc5626
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 1 deletion.
91 changes: 91 additions & 0 deletions algorithms/graph/bellman_ford.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/**
* Copyright (C) 2014 Tayllan Búrigo
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
'use strict';

/**
* Calculates the shortest paths in a graph to every node
* from the node 'startNode' with Bellman-Ford's algorithm
*
* Worst Case Complexity: O(|V| * |E|), where |V| is the number of
* vertices and |E| is the number of edges in the graph
*
* @param Object 'graph' An adjacency list representing the graph
* @param String 'startNode' The starting node
* @return Object the minimum distance to reach every vertice of
* the graph starting in 'startNode', or an empty object if there
* exists a Negative-Weighted Cycle in the graph
*/
var bellmanFord = function(graph, startNode) {
var minDistance = {};
var edges = [];
var adjacencyListSize = 0;

// Add all the edges from the graph to the 'edges' array
graph.vertices.forEach(function (s) {
graph.neighbors(s).forEach(function(t) {
edges.push({
source: s,
target: t,
weight: graph.edge(s, t)
});
});

minDistance[s] = Infinity;
++adjacencyListSize;
});

minDistance[startNode] = 0;

var edgesSize = edges.length;
var sourceDistance;
var targetDistance;

for (var i = 0; i < adjacencyListSize - 1; i++) {
for (var j = 0; j < edgesSize; j++) {
sourceDistance = minDistance[edges[j].source] + edges[j].weight;
targetDistance = minDistance[edges[j].target];

if (sourceDistance < targetDistance) {
minDistance[edges[j].target] = sourceDistance;
}
}
}

for (i = 0; i < edgesSize; i++) {
sourceDistance = minDistance[edges[i].source] + edges[i].weight;
targetDistance = minDistance[edges[i].target];

if (sourceDistance < targetDistance) {

// Empty 'distance' object indicates Negative-Weighted Cycle
return {
distance: {}
};
}
}

return {
distance: minDistance
};
};

module.exports = bellmanFord;
3 changes: 2 additions & 1 deletion main.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
var lib = {
Graph: {
topologicalSort: require('./algorithms/graph/topological_sort'),
dijkstra: require('./algorithms/graph/dijkstra')
dijkstra: require('./algorithms/graph/dijkstra'),
bellmanFord: require('./algorithms/graph/bellman_ford')
},
Math: {
fibonacci: require('./algorithms/math/fibonacci'),
Expand Down
56 changes: 56 additions & 0 deletions test/algorithms/graph/bellman_ford.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/**
* Copyright (C) 2014 Tayllan Búrigo
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"], to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
'use strict';

var bellmanFord = require('../../../algorithms/graph/bellman_ford'),
Graph = require('../../../data_structures/graph'),
assert = require('assert');

describe('Bellman-Ford Algorithm', function () {
it('should return the shortest paths to all nodes from a given origin',
function () {
var graph = new Graph(true);

graph.addEdge('a', 'b', -1);
graph.addEdge('a', 'c', 4);
graph.addEdge('b', 'c', 3);
graph.addEdge('b', 'd', 2);
graph.addEdge('b', 'e', 2);
graph.addEdge('d', 'b', 1);
graph.addEdge('e', 'd', -3);
graph.addEdge('d', 'c', 5);

var shortestPaths = bellmanFord(graph, 'a');

assert.equal(shortestPaths.distance.a, 0);
assert.equal(shortestPaths.distance.d, -2);
assert.equal(shortestPaths.distance.e, 1);

// It'll cause a Negative-Weighted Cycle.
graph.addEdge('c', 'a', -9);

shortestPaths = bellmanFord(graph, 'a');

// The 'distance' object is empty
assert.equal(shortestPaths.distance.a, undefined);
});
});

0 comments on commit ebc5626

Please sign in to comment.