Skip to content

Commit 5788575

Browse files
committedMay 3, 2018
Add Bellman-Ford.
1 parent c97e472 commit 5788575

File tree

8 files changed

+142
-5
lines changed

8 files changed

+142
-5
lines changed
 

‎README.md

+4-3
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@
6565
* **Graph**
6666
* [Depth-First Search](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/depth-first-search) (DFS)
6767
* [Breadth-First Search](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/breadth-first-search) (BFS)
68-
* [Dijkstra Algorithm](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/dijkstra) - finding shortest path
69-
* Bellman Ford
68+
* [Dijkstra Algorithm](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/dijkstra) - finding shortest path to all graph vertices
69+
* [Bellman-Ford Algorithm](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/bellman-ford) - finding shortest path to all graph vertices
7070
* Detect Cycle
7171
* Topological Sorting
7272
* Eulerian path, Eulerian circuit
@@ -84,7 +84,7 @@
8484

8585
* **Greedy**
8686
* [Unbound Knapsack Problem](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/knapsack-problem)
87-
* [Dijkstra Algorithm](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/dijkstra) - finding shortest path
87+
* [Dijkstra Algorithm](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/dijkstra) - finding shortest path to all graph vertices
8888
* **Divide and Conquer**
8989
* [Euclidean Algorithm](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/euclidean-algorithm) - calculate the Greatest Common Divisor (GCD)
9090
* [Permutations](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/permutations) (with and without repetitions)
@@ -103,6 +103,7 @@
103103
* [0/1 Knapsack Problem](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/knapsack-problem)
104104
* [Integer Partition](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/integer-partition)
105105
* [Maximum Subarray](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/maximum-subarray)
106+
* [Bellman-Ford Algorithm](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/bellman-ford) - finding shortest path to all graph vertices
106107
* **Backtracking**
107108
* **Branch & Bound**
108109

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Bellman–Ford Algorithm
2+
3+
The Bellman–Ford algorithm is an algorithm that computes shortest
4+
paths from a single source vertex to all of the other vertices
5+
in a weighted digraph. It is slower than Dijkstra's algorithm
6+
for the same problem, but more versatile, as it is capable of
7+
handling graphs in which some of the edge weights are negative
8+
numbers.
9+
10+
![Bellman-Ford](https://upload.wikimedia.org/wikipedia/commons/2/2e/Shortest_path_Dijkstra_vs_BellmanFord.gif)
11+
12+
## Complexity
13+
14+
Worst-case performance `O(|V||E|)`
15+
Best-case performance `O(|E|)`
16+
Worst-case space complexity `O(|V|)`
17+
18+
## References
19+
20+
- [Wikipedia](https://en.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm)
21+
- [On YouTube by Michael Sambol](https://www.youtube.com/watch?v=obWXjtg0L64)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import GraphVertex from '../../../../data-structures/graph/GraphVertex';
2+
import GraphEdge from '../../../../data-structures/graph/GraphEdge';
3+
import Graph from '../../../../data-structures/graph/Graph';
4+
import bellmanFord from '../bellmanFord';
5+
6+
describe('bellmanFord', () => {
7+
it('should find minimum paths to all vertices', () => {
8+
const vertexS = new GraphVertex('S');
9+
const vertexE = new GraphVertex('E');
10+
const vertexA = new GraphVertex('A');
11+
const vertexD = new GraphVertex('D');
12+
const vertexB = new GraphVertex('B');
13+
const vertexC = new GraphVertex('C');
14+
const vertexH = new GraphVertex('H');
15+
16+
const edgeSE = new GraphEdge(vertexS, vertexE, 8);
17+
const edgeSA = new GraphEdge(vertexS, vertexA, 10);
18+
const edgeED = new GraphEdge(vertexE, vertexD, 1);
19+
const edgeDA = new GraphEdge(vertexD, vertexA, -4);
20+
const edgeDC = new GraphEdge(vertexD, vertexC, -1);
21+
const edgeAC = new GraphEdge(vertexA, vertexC, 2);
22+
const edgeCB = new GraphEdge(vertexC, vertexB, -2);
23+
const edgeBA = new GraphEdge(vertexB, vertexA, 1);
24+
25+
const graph = new Graph(true);
26+
graph
27+
.addVertex(vertexH)
28+
.addEdge(edgeSE)
29+
.addEdge(edgeSA)
30+
.addEdge(edgeED)
31+
.addEdge(edgeDA)
32+
.addEdge(edgeDC)
33+
.addEdge(edgeAC)
34+
.addEdge(edgeCB)
35+
.addEdge(edgeBA);
36+
37+
const { distances, previousVertices } = bellmanFord(graph, vertexS);
38+
39+
expect(distances).toEqual({
40+
H: Infinity,
41+
S: 0,
42+
A: 5,
43+
B: 5,
44+
C: 7,
45+
D: 9,
46+
E: 8,
47+
});
48+
49+
expect(previousVertices.H).toBeNull();
50+
expect(previousVertices.S).toBeNull();
51+
expect(previousVertices.B.getKey()).toBe('C');
52+
expect(previousVertices.C.getKey()).toBe('A');
53+
expect(previousVertices.A.getKey()).toBe('D');
54+
expect(previousVertices.D.getKey()).toBe('E');
55+
});
56+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/**
2+
* @param {Graph} graph
3+
* @param {GraphVertex} startVertex
4+
* @return {{distances, previousVertices}}
5+
*/
6+
export default function bellmanFord(graph, startVertex) {
7+
const distances = {};
8+
const previousVertices = {};
9+
10+
// Init all distances with infinity assuming that currently we can't reach
11+
// any of the vertices except start one.
12+
distances[startVertex.getKey()] = 0;
13+
graph.getAllVertices().forEach((vertex) => {
14+
previousVertices[vertex.getKey()] = null;
15+
if (vertex.getKey() !== startVertex.getKey()) {
16+
distances[vertex.getKey()] = Infinity;
17+
}
18+
});
19+
20+
// We need (|V| - 1) iterations.
21+
for (let iteration = 0; iteration < (graph.getAllVertices().length - 1); iteration += 1) {
22+
// During each iteration go through all vertices.
23+
Object.keys(distances).forEach((vertexKey) => {
24+
const vertex = graph.getVertexByKey(vertexKey);
25+
26+
// Go through all vertex edges.
27+
graph.getNeighbors(vertex).forEach((neighbor) => {
28+
const edge = graph.findEdge(vertex, neighbor);
29+
// Find out if the distance to the neighbor is shorter in this iteration
30+
// then in previous one.
31+
const distanceToVertex = distances[vertex.getKey()];
32+
const distanceToNeighbor = distanceToVertex + edge.weight;
33+
if (distanceToNeighbor < distances[neighbor.getKey()]) {
34+
distances[neighbor.getKey()] = distanceToNeighbor;
35+
previousVertices[neighbor.getKey()] = vertex;
36+
}
37+
});
38+
});
39+
}
40+
41+
return {
42+
distances,
43+
previousVertices,
44+
};
45+
}

‎src/algorithms/graph/dijkstra/__test__/dijkstra.test.js

+2
Original file line numberDiff line numberDiff line change
@@ -61,5 +61,7 @@ describe('dijkstra', () => {
6161
expect(previousVertices.B.getKey()).toBe('A');
6262
expect(previousVertices.G.getKey()).toBe('E');
6363
expect(previousVertices.C.getKey()).toBe('A');
64+
expect(previousVertices.A).toBeNull();
65+
expect(previousVertices.H).toBeNull();
6466
});
6567
});

‎src/algorithms/graph/dijkstra/dijkstra.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ export default function dijkstra(graph, startVertex) {
1212

1313
// Init all distances with infinity assuming that currently we can't reach
1414
// any of the vertices except start one.
15-
Object.keys(graph.vertices).forEach((vertexKey) => {
16-
distances[vertexKey] = Infinity;
15+
graph.getAllVertices().forEach((vertex) => {
16+
distances[vertex.getKey()] = Infinity;
17+
previousVertices[vertex.getKey()] = null;
1718
});
1819
distances[startVertex.getKey()] = 0;
1920

‎src/data-structures/graph/Graph.js

+7
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,13 @@ export default class Graph {
3232
return vertex.getNeighbors();
3333
}
3434

35+
/**
36+
* @return {GraphVertex[]}
37+
*/
38+
getAllVertices() {
39+
return Object.values(this.vertices);
40+
}
41+
3542
/**
3643
* @param {GraphEdge} edge
3744
* @returns {Graph}

‎src/data-structures/graph/__test__/Graph.test.js

+4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ describe('Graph', () => {
2828

2929
graph.addEdge(edgeAB);
3030

31+
expect(graph.getAllVertices().length).toBe(2);
32+
expect(graph.getAllVertices()[0]).toEqual(vertexA);
33+
expect(graph.getAllVertices()[1]).toEqual(vertexB);
34+
3135
const graphVertexA = graph.findVertexByKey(vertexA.getKey());
3236
const graphVertexB = graph.findVertexByKey(vertexB.getKey());
3337

0 commit comments

Comments
 (0)
Please sign in to comment.