Skip to content

Commit 6a22abc

Browse files
authored
Merge pull request #3 from Gapur/graph
Graph
2 parents c28acb8 + 3303eed commit 6a22abc

24 files changed

+1220
-5
lines changed

algorithms/graph/depthFirstSearch.js

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
function initCallbacks(callbacks = {}) {
2+
const initiatedCallback = callbacks;
3+
4+
const stubCallback = () => {};
5+
6+
const allowTraversalCallback = (
7+
() => {
8+
const seen = {};
9+
return ({ nextVertex }) => {
10+
if (!seen[nextVertex.getKey()]) {
11+
seen[nextVertex.getKey()] = true;
12+
return true;
13+
}
14+
return false;
15+
};
16+
}
17+
)();
18+
19+
initiatedCallback.allowTraversal = callbacks.allowTraversal || allowTraversalCallback;
20+
initiatedCallback.enterVertex = callbacks.enterVertex || stubCallback;
21+
initiatedCallback.leaveVertex = callbacks.leaveVertex || stubCallback;
22+
23+
return initiatedCallback;
24+
}
25+
26+
function depthFirstSearchRecursive(graph, currentVertex, previousVertex, callbacks) {
27+
callbacks.enterVertex({ currentVertex, previousVertex });
28+
29+
graph.getNeighbors(currentVertex).forEach((nextVertex) => {
30+
if (callbacks.allowTraversal({ previousVertex, currentVertex, nextVertex })) {
31+
depthFirstSearchRecursive(graph, nextVertex, currentVertex, callbacks);
32+
}
33+
});
34+
35+
callbacks.leaveVertex({ currentVertex, previousVertex });
36+
}
37+
38+
module.exports = function depthFirstSearch(graph, startVertex, callbacks) {
39+
const previousVertex = null;
40+
depthFirstSearchRecursive(graph, startVertex, previousVertex, initCallbacks(callbacks));
41+
};

algorithms/graph/dijkstra.js

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
const PriorityQueue = require('../../data-structures/priority-queue/PriorityQueue');
2+
3+
module.exports = function dijkstra(graph, startVertex) {
4+
// Init helper variables that we will need for Dijkstra algorithm.
5+
const distances = {};
6+
const visitedVertices = {};
7+
const previousVertices = {};
8+
const queue = new PriorityQueue();
9+
10+
// Init all distances with infinity assuming that currently we can't reach
11+
// any of the vertices except the start one.
12+
graph.getAllVertices().forEach((vertex) => {
13+
distances[vertex.getKey()] = Infinity;
14+
previousVertices[vertex.getKey()] = null;
15+
});
16+
17+
// We are already at the startVertex so the distance to it is zero.
18+
distances[startVertex.getKey()] = 0;
19+
20+
// Init vertices queue.
21+
queue.add(startVertex, distances[startVertex.getKey()]);
22+
23+
// Iterate over the priority queue of vertices until it is empty.
24+
while (!queue.isEmpty()) {
25+
// Fetch next closest vertex.
26+
const currentVertex = queue.poll();
27+
28+
// Iterate over every unvisited neighbor of the current vertex.
29+
currentVertex.getNeighbors().forEach((neighbor) => {
30+
// Don't visit already visited vertices.
31+
if (!visitedVertices[neighbor.getKey()]) {
32+
// Update distances to every neighbor from current vertex.
33+
const edge = graph.findEdge(currentVertex, neighbor);
34+
35+
const existingDistanceToNeighbor = distances[neighbor.getKey()];
36+
const distanceToNeighborFromCurrent = distances[currentVertex.getKey()] + edge.weight;
37+
38+
// If we've found shorter path to the neighbor - update it.
39+
if (distanceToNeighborFromCurrent < existingDistanceToNeighbor) {
40+
distances[neighbor.getKey()] = distanceToNeighborFromCurrent;
41+
42+
// Change priority of the neighbor in a queue since it might have became closer.
43+
if (queue.hasValue(neighbor)) {
44+
queue.changePriority(neighbor, distances[neighbor.getKey()]);
45+
}
46+
47+
// Remember previous closest vertex.
48+
previousVertices[neighbor.getKey()] = currentVertex;
49+
}
50+
51+
// Add neighbor to the queue for further visiting.
52+
if (!queue.hasValue(neighbor)) {
53+
queue.add(neighbor, distances[neighbor.getKey()]);
54+
}
55+
}
56+
});
57+
58+
// Add current vertex to visited ones to avoid visiting it again later.
59+
visitedVertices[currentVertex.getKey()] = currentVertex;
60+
}
61+
62+
// Return the set of shortest distances to all vertices and the set of
63+
// shortest paths to all vertices in a graph.
64+
return {
65+
distances,
66+
previousVertices,
67+
};
68+
};

algorithms/graph/floydWarshall.js

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
module.exports = function floydWarshall(graph) {
2+
// Get all graph vertices.
3+
const vertices = graph.getAllVertices();
4+
5+
// Init previous vertices matrix with nulls meaning that there are no
6+
// previous vertices exist that will give us shortest path.
7+
const nextVertices = Array(vertices.length).fill(null).map(() => {
8+
return Array(vertices.length).fill(null);
9+
});
10+
11+
// Init distances matrix with Infinities meaning there are no paths
12+
// between vertices exist so far.
13+
const distances = Array(vertices.length).fill(null).map(() => {
14+
return Array(vertices.length).fill(Infinity);
15+
});
16+
17+
// Init distance matrix with the distance we already now (from existing edges).
18+
// And also init previous vertices from the edges.
19+
vertices.forEach((startVertex, startIndex) => {
20+
vertices.forEach((endVertex, endIndex) => {
21+
if (startVertex === endVertex) {
22+
// Distance to the vertex itself is 0.
23+
distances[startIndex][endIndex] = 0;
24+
} else {
25+
// Find edge between the start and end vertices.
26+
const edge = graph.findEdge(startVertex, endVertex);
27+
28+
if (edge) {
29+
// There is an edge from vertex with startIndex to vertex with endIndex.
30+
// Save distance and previous vertex.
31+
distances[startIndex][endIndex] = edge.weight;
32+
nextVertices[startIndex][endIndex] = startVertex;
33+
} else {
34+
distances[startIndex][endIndex] = Infinity;
35+
}
36+
}
37+
});
38+
});
39+
40+
// Now let's go to the core of the algorithm.
41+
// Let's all pair of vertices (from start to end ones) and try to check if there
42+
// is a shorter path exists between them via middle vertex. Middle vertex may also
43+
// be one of the graph vertices. As you may see now we're going to have three
44+
// loops over all graph vertices: for start, end and middle vertices.
45+
vertices.forEach((middleVertex, middleIndex) => {
46+
// Path starts from startVertex with startIndex.
47+
vertices.forEach((startVertex, startIndex) => {
48+
// Path ends to endVertex with endIndex.
49+
vertices.forEach((endVertex, endIndex) => {
50+
// Compare existing distance from startVertex to endVertex, with distance
51+
// from startVertex to endVertex but via middleVertex.
52+
// Save the shortest distance and previous vertex that allows
53+
// us to have this shortest distance.
54+
const distViaMiddle = distances[startIndex][middleIndex] + distances[middleIndex][endIndex];
55+
56+
if (distances[startIndex][endIndex] > distViaMiddle) {
57+
// We've found a shortest pass via middle vertex.
58+
distances[startIndex][endIndex] = distViaMiddle;
59+
nextVertices[startIndex][endIndex] = middleVertex;
60+
}
61+
});
62+
});
63+
});
64+
65+
// Shortest distance from x to y: distance[x][y].
66+
// Next vertex after x one in path from x to y: nextVertices[x][y].
67+
return { distances, nextVertices };
68+
};

0 commit comments

Comments
 (0)