Skip to content

Commit 5c5a124

Browse files
author
FSou1
committed
Add the basic implementation of the Dijkstra's algorithm
1 parent 1a955d4 commit 5c5a124

File tree

9 files changed

+211
-8
lines changed

9 files changed

+211
-8
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ An algorithm is a finite sequence of well-defined, computer-implementable instru
3131
* **Graph**
3232
* [Breadth-first search](src/algorithms/graph/breadth-first-search) - traverse a graph, explore neighbor vertices first;
3333
* [Depth-first search](src/algorithms/graph/depth-first-search) - traverse a graph, explore descendant vertices first;
34+
* [Dijkstra](src/algorithms/graph/dijkstra) - find the shortest path between two vertices in a graph, return a shortest-path tree;
3435

3536
## How to use this repository
3637

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"description": "Algorithms and data structures implemented in TypeScript",
55
"author": "Maxim Zhukov (https://www.linkedin.com/in/maxim-zhukov-0648a8b5)",
66
"scripts": {
7-
"lint": "eslint ./src/*",
7+
"lint": "eslint ./src/**/*.ts",
88
"test": "jest"
99
},
1010
"repository": {
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Dijkstra
2+
3+
Dijkstra's algorithm (or Dijkstra's Shortest Path First algorithm, SPF algorithm) is an algorithm for finding the shortest paths between nodes in a graph, which may represent, for example, road networks. It was conceived by computer scientist Edsger W. Dijkstra in 1956 and published three years later.
4+
5+
The algorithm exists in many variants. Dijkstra's original algorithm found the shortest path between two given 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.
6+
7+
## Applications
8+
9+
* Searching for a shortest path
10+
* Build an optimal path at geographical maps
11+
* Network routing protocols
12+
13+
## Complexity
14+
15+
**Time Complexity**: TBD.
16+
17+
**Space Complexity**: TBD.
18+
19+
## References
20+
21+
- [Youtube](https://www.youtube.com/watch?v=2E7MmKv0Y24);
22+
- [Wikipedia](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import {Graph} from '../../../../data-structures/graph/graph';
2+
import {GraphVertex} from '../../../../data-structures/graph/graphVertex';
3+
import {GraphEdge} from '../../../../data-structures/graph/graphEdge';
4+
import {dijkstra} from '../dijsktra';
5+
6+
test('should return shortest paths to vertices', () => {
7+
const graph = new Graph(true);
8+
9+
const vertexA = new GraphVertex('A');
10+
const vertexB = new GraphVertex('B');
11+
const vertexC = new GraphVertex('C');
12+
const vertexD = new GraphVertex('D');
13+
const vertexE = new GraphVertex('E');
14+
const vertexF = new GraphVertex('F');
15+
const vertexG = new GraphVertex('G');
16+
const vertexH = new GraphVertex('H');
17+
18+
const edgeAB = new GraphEdge(vertexA, vertexB, 4);
19+
const edgeAE = new GraphEdge(vertexA, vertexE, 7);
20+
const edgeAC = new GraphEdge(vertexA, vertexC, 3);
21+
const edgeBC = new GraphEdge(vertexB, vertexC, 6);
22+
const edgeBD = new GraphEdge(vertexB, vertexD, 5);
23+
const edgeEC = new GraphEdge(vertexE, vertexC, 8);
24+
const edgeED = new GraphEdge(vertexE, vertexD, 2);
25+
const edgeDC = new GraphEdge(vertexD, vertexC, 11);
26+
const edgeDG = new GraphEdge(vertexD, vertexG, 10);
27+
const edgeDF = new GraphEdge(vertexD, vertexF, 2);
28+
const edgeFG = new GraphEdge(vertexF, vertexG, 3);
29+
const edgeEG = new GraphEdge(vertexE, vertexG, 5);
30+
31+
graph
32+
.addVertex(vertexH)
33+
.addEdge(edgeAB)
34+
.addEdge(edgeAE)
35+
.addEdge(edgeAC)
36+
.addEdge(edgeBC)
37+
.addEdge(edgeBD)
38+
.addEdge(edgeEC)
39+
.addEdge(edgeED)
40+
.addEdge(edgeDC)
41+
.addEdge(edgeDG)
42+
.addEdge(edgeDF)
43+
.addEdge(edgeFG)
44+
.addEdge(edgeEG);
45+
46+
const {dist, prev} = dijkstra(graph, vertexA);
47+
48+
expect(dist['H']).toBe(Infinity);
49+
expect(dist['A']).toBe(0);
50+
expect(dist['B']).toBe(4);
51+
expect(dist['E']).toBe(7);
52+
expect(dist['C']).toBe(3);
53+
expect(dist['D']).toBe(9);
54+
expect(dist['G']).toBe(12);
55+
expect(dist['F']).toBe(11);
56+
57+
expect(prev['F']).toBe('D');
58+
expect(prev['D']).toBe('B');
59+
expect(prev['B']).toBe('A');
60+
expect(prev['G']).toBe('E');
61+
expect(prev['C']).toBe('A');
62+
expect(prev['A']).toBeUndefined();
63+
expect(prev['H']).toBeUndefined();
64+
});
+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/* eslint-disable no-unused-vars */
2+
import {Graph} from '../../../data-structures/graph/graph';
3+
import {GraphVertex} from '../../../data-structures/graph/graphVertex';
4+
import {Queue} from '../../../data-structures/queue/queue';
5+
6+
/**
7+
*
8+
*
9+
* @export
10+
* @param {Graph} graph
11+
* @param {GraphVertex} source
12+
* @return {{
13+
* dist: Map<string, number>,
14+
* prev: Map<string, string>
15+
* }}
16+
*/
17+
export function dijkstra(
18+
graph: Graph,
19+
source: GraphVertex,
20+
): {
21+
dist: Map<string, number>;
22+
prev: Map<string, string>;
23+
} {
24+
const dist = new Map<string, number>();
25+
const prev = new Map<string, string>();
26+
const visited = new Map<string, boolean>();
27+
28+
for (const vertex of graph.getVertices()) {
29+
dist[vertex.getKey()] = Infinity;
30+
prev[vertex.getKey()] = undefined;
31+
}
32+
dist[source.getKey()] = 0;
33+
34+
const queue = new Queue<GraphVertex>();
35+
queue.enqueue(source);
36+
while (!queue.isEmpty()) {
37+
const currentVertex = queue.dequeue();
38+
39+
const neighbors = currentVertex.getNeighbors();
40+
for (const neighbor of neighbors) {
41+
if (!visited[neighbor.getKey()]) {
42+
const edge = graph.findEdge(currentVertex, neighbor);
43+
44+
const path = dist[currentVertex.getKey()] + edge.weight;
45+
if (path < dist[neighbor.getKey()]) {
46+
// a new s.p. has been found
47+
dist[neighbor.getKey()] = path;
48+
prev[neighbor.getKey()] = currentVertex.getKey();
49+
}
50+
}
51+
}
52+
53+
// mark as visited
54+
visited[currentVertex.getKey()] = true;
55+
56+
// enqueue next vertex
57+
let minDistance = Infinity;
58+
let nextVertex = null;
59+
for (const vertex of graph.getVertices()) {
60+
if (!visited[vertex.getKey()]) {
61+
if (dist[vertex.getKey()] < minDistance) {
62+
minDistance = dist[vertex.getKey()];
63+
nextVertex = vertex;
64+
}
65+
}
66+
}
67+
68+
// TODO: replace with priority queue
69+
if (nextVertex) {
70+
queue.enqueue(nextVertex);
71+
}
72+
}
73+
74+
return {dist, prev};
75+
}

src/algorithms/search/peak-finder/2d/__tests__/peakFinder2d.test.ts

-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ test('a peak of [2x2] is 3', () => {
1414
[2, 3],
1515
];
1616
const peak = 3;
17-
debugger;
1817
expect(findPeak(arr)).toBe(peak);
1918
});
2019

src/data-structures/graph/graph.ts

+27-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import {GraphEdge} from './graphEdge';
99
* @class Graph
1010
*/
1111
export class Graph {
12-
directed: boolean;
13-
verticies: {};
12+
private directed: boolean;
13+
private verticies: {};
1414

1515
/**
1616
* Creates an instance of Graph.
@@ -69,6 +69,16 @@ export class Graph {
6969
return this.verticies[vertex.getKey()] || null;
7070
}
7171

72+
/**
73+
*
74+
*
75+
* @return {GraphVertex[]}
76+
* @memberof Graph
77+
*/
78+
getVertices(): GraphVertex[] {
79+
return Object.keys(this.verticies).map((k) => this.verticies[k]) || null;
80+
}
81+
7282
/**
7383
* @param {GraphVertex} vertex
7484
* @return {GraphVertex[]}
@@ -78,6 +88,21 @@ export class Graph {
7888
return this.getVertex(vertex).getNeighbors();
7989
}
8090

91+
/**
92+
* @param {GraphVertex} start
93+
* @param {GraphVertex} end
94+
* @return {GraphEdge}
95+
* @memberof Graph
96+
*/
97+
findEdge(start: GraphVertex, end: GraphVertex): GraphEdge {
98+
const vertex = this.getVertex(start);
99+
if (!vertex) {
100+
return null;
101+
}
102+
103+
return vertex.findEdge(end);
104+
}
105+
81106
/**
82107
* @return {string}
83108
* @memberof Graph

src/data-structures/graph/graphEdge.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,18 @@ import {GraphVertex} from './graphVertex';
1010
export class GraphEdge {
1111
startVertex: GraphVertex;
1212
endVertex: GraphVertex;
13+
weight: number;
1314

1415
/**
1516
*Creates an instance of GraphEdge.
1617
* @param {GraphVertex} startVertex
1718
* @param {GraphVertex} endVertex
19+
* @param {number} [weight=0]
1820
* @memberof GraphEdge
1921
*/
20-
constructor(startVertex: GraphVertex, endVertex: GraphVertex) {
22+
constructor(startVertex: GraphVertex, endVertex: GraphVertex, weight = 0) {
2123
this.startVertex = startVertex;
2224
this.endVertex = endVertex;
25+
this.weight = weight;
2326
}
2427
}

src/data-structures/graph/graphVertex.ts

+17-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
// eslint-disable-next-line no-unused-vars
1+
/* eslint-disable no-unused-vars */
22
import {GraphEdge} from './graphEdge';
3+
import {Graph} from './graph';
34

45
/**
56
*
@@ -8,8 +9,8 @@ import {GraphEdge} from './graphEdge';
89
* @class GraphVertex
910
*/
1011
export class GraphVertex {
11-
key: string;
12-
edges: GraphEdge[];
12+
private key: string;
13+
private edges: GraphEdge[];
1314

1415
/**
1516
*Creates an instance of GraphVertex.
@@ -39,6 +40,19 @@ export class GraphVertex {
3940
return this;
4041
}
4142

43+
/**
44+
* @param {GraphVertex} vertex
45+
* @return {GraphEdge}
46+
* @memberof GraphVertex
47+
*/
48+
findEdge(vertex: GraphVertex): GraphEdge {
49+
const edge = this.edges.filter((edge) => {
50+
return edge.startVertex === vertex || edge.endVertex === vertex;
51+
});
52+
53+
return edge[0] ?? null;
54+
}
55+
4256
/**
4357
* @return {GraphVertex[]}
4458
* @memberof GraphVertex

0 commit comments

Comments
 (0)