Skip to content

Commit

Permalink
Incoming features from graph algorithms
Browse files Browse the repository at this point in the history
  • Loading branch information
brunolnetto committed Jan 22, 2022
1 parent fbccf56 commit dfa5632
Show file tree
Hide file tree
Showing 32 changed files with 2,338 additions and 96 deletions.
21 changes: 21 additions & 0 deletions algorithms/bellman-ford/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Bellman–Ford Algorithm

The Bellman–Ford algorithm is an algorithm that computes shortest
paths from a single source vertex to all of the other vertices
in a weighted digraph. It is slower than Dijkstra's algorithm
for the same problem, but more versatile, as it is capable of
handling graphs in which some of the edge weights are negative
numbers.

![Bellman-Ford](https://upload.wikimedia.org/wikipedia/commons/2/2e/Shortest_path_Dijkstra_vs_BellmanFord.gif)

## Complexity

Worst-case performance `O(|V||E|)`
Best-case performance `O(|E|)`
Worst-case space complexity `O(|V|)`

## References

- [Wikipedia](https://en.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm)
- [On YouTube by Michael Sambol](https://www.youtube.com/watch?v=obWXjtg0L64&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
117 changes: 117 additions & 0 deletions algorithms/bellman-ford/__test__/bellmanFord.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import GraphVertex from '../../../../data-structures/graph/GraphVertex';
import GraphEdge from '../../../../data-structures/graph/GraphEdge';
import Graph from '../../../../data-structures/graph/Graph';
import bellmanFord from '../bellmanFord';

describe('bellmanFord', () => {
it('should find minimum paths to all vertices for undirected graph', () => {
const vertexA = new GraphVertex('A');
const vertexB = new GraphVertex('B');
const vertexC = new GraphVertex('C');
const vertexD = new GraphVertex('D');
const vertexE = new GraphVertex('E');
const vertexF = new GraphVertex('F');
const vertexG = new GraphVertex('G');
const vertexH = new GraphVertex('H');

const edgeAB = new GraphEdge(vertexA, vertexB, 4);
const edgeAE = new GraphEdge(vertexA, vertexE, 7);
const edgeAC = new GraphEdge(vertexA, vertexC, 3);
const edgeBC = new GraphEdge(vertexB, vertexC, 6);
const edgeBD = new GraphEdge(vertexB, vertexD, 5);
const edgeEC = new GraphEdge(vertexE, vertexC, 8);
const edgeED = new GraphEdge(vertexE, vertexD, 2);
const edgeDC = new GraphEdge(vertexD, vertexC, 11);
const edgeDG = new GraphEdge(vertexD, vertexG, 10);
const edgeDF = new GraphEdge(vertexD, vertexF, 2);
const edgeFG = new GraphEdge(vertexF, vertexG, 3);
const edgeEG = new GraphEdge(vertexE, vertexG, 5);

const graph = new Graph();
graph
.addVertex(vertexH)
.addEdge(edgeAB)
.addEdge(edgeAE)
.addEdge(edgeAC)
.addEdge(edgeBC)
.addEdge(edgeBD)
.addEdge(edgeEC)
.addEdge(edgeED)
.addEdge(edgeDC)
.addEdge(edgeDG)
.addEdge(edgeDF)
.addEdge(edgeFG)
.addEdge(edgeEG);

const { distances, previousVertices } = bellmanFord(graph, vertexA);

expect(distances).toEqual({
H: Infinity,
A: 0,
B: 4,
E: 7,
C: 3,
D: 9,
G: 12,
F: 11,
});

expect(previousVertices.F.getKey()).toBe('D');
expect(previousVertices.D.getKey()).toBe('B');
expect(previousVertices.B.getKey()).toBe('A');
expect(previousVertices.G.getKey()).toBe('E');
expect(previousVertices.C.getKey()).toBe('A');
expect(previousVertices.A).toBeNull();
expect(previousVertices.H).toBeNull();
});

it('should find minimum paths to all vertices for directed graph with negative edge weights', () => {
const vertexS = new GraphVertex('S');
const vertexE = new GraphVertex('E');
const vertexA = new GraphVertex('A');
const vertexD = new GraphVertex('D');
const vertexB = new GraphVertex('B');
const vertexC = new GraphVertex('C');
const vertexH = new GraphVertex('H');

const edgeSE = new GraphEdge(vertexS, vertexE, 8);
const edgeSA = new GraphEdge(vertexS, vertexA, 10);
const edgeED = new GraphEdge(vertexE, vertexD, 1);
const edgeDA = new GraphEdge(vertexD, vertexA, -4);
const edgeDC = new GraphEdge(vertexD, vertexC, -1);
const edgeAC = new GraphEdge(vertexA, vertexC, 2);
const edgeCB = new GraphEdge(vertexC, vertexB, -2);
const edgeBA = new GraphEdge(vertexB, vertexA, 1);

const graph = new Graph(true);
graph
.addVertex(vertexH)
.addEdge(edgeSE)
.addEdge(edgeSA)
.addEdge(edgeED)
.addEdge(edgeDA)
.addEdge(edgeDC)
.addEdge(edgeAC)
.addEdge(edgeCB)
.addEdge(edgeBA);

const { distances, previousVertices } = bellmanFord(graph, vertexS);

expect(distances).toEqual({
H: Infinity,
S: 0,
A: 5,
B: 5,
C: 7,
D: 9,
E: 8,
});

expect(previousVertices.H).toBeNull();
expect(previousVertices.S).toBeNull();
expect(previousVertices.B.getKey()).toBe('C');
expect(previousVertices.C.getKey()).toBe('A');
expect(previousVertices.A.getKey()).toBe('D');
expect(previousVertices.D.getKey()).toBe('E');
});
});
45 changes: 45 additions & 0 deletions algorithms/bellman-ford/bellmanFord.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* @param {Graph} graph
* @param {GraphVertex} startVertex
* @return {{distances, previousVertices}}
*/
export default function bellmanFord(graph, startVertex) {
const distances = {};
const previousVertices = {};

// Init all distances with infinity assuming that currently we can't reach
// any of the vertices except start one.
distances[startVertex.getKey()] = 0;
graph.getAllVertices().forEach((vertex) => {
previousVertices[vertex.getKey()] = null;
if (vertex.getKey() !== startVertex.getKey()) {
distances[vertex.getKey()] = Infinity;
}
});

// We need (|V| - 1) iterations.
for (let iteration = 0; iteration < (graph.getAllVertices().length - 1); iteration += 1) {
// During each iteration go through all vertices.
Object.keys(distances).forEach((vertexKey) => {
const vertex = graph.getVertexByKey(vertexKey);

// Go through all vertex edges.
graph.getNeighbors(vertex).forEach((neighbor) => {
const edge = graph.findEdge(vertex, neighbor);
// Find out if the distance to the neighbor is shorter in this iteration
// then in previous one.
const distanceToVertex = distances[vertex.getKey()];
const distanceToNeighbor = distanceToVertex + edge.weight;
if (distanceToNeighbor < distances[neighbor.getKey()]) {
distances[neighbor.getKey()] = distanceToNeighbor;
previousVertices[neighbor.getKey()] = vertex;
}
});
});
}

return {
distances,
previousVertices,
};
}
60 changes: 0 additions & 60 deletions algorithms/detect-cycle/README.md

This file was deleted.

This file was deleted.

25 changes: 25 additions & 0 deletions algorithms/dijkstra/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Dijkstra's Algorithm

Dijkstra's algorithm is an algorithm for finding the shortest
paths between nodes in a graph, which may represent, for example,
road networks.

The algorithm exists in many variants; Dijkstra's original variant
found the shortest path between two nodes, but a more common
variant fixes a single node as the "source" node and finds
shortest paths from the source to all other nodes in the graph,
producing a shortest-path tree.

![Dijkstra](https://upload.wikimedia.org/wikipedia/commons/5/57/Dijkstra_Animation.gif)

Dijkstra's algorithm to find the shortest path between `a` and `b`.
It picks the unvisited vertex with the lowest distance,
calculates the distance through it to each unvisited neighbor,
and updates the neighbor's distance if smaller. Mark visited
(set to red) when done with neighbors.

## References

- [Wikipedia](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm)
- [On YouTube by Nathaniel Fan](https://www.youtube.com/watch?v=gdmfOwyQlcI&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
- [On YouTube by Tushar Roy](https://www.youtube.com/watch?v=lAXZGERcDf4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
Loading

0 comments on commit dfa5632

Please sign in to comment.