Skip to content

Commit ab0511c

Browse files
committed
Improve Dijkstra's shortest path performance
1 parent dc17f40 commit ab0511c

File tree

1 file changed

+58
-30
lines changed

1 file changed

+58
-30
lines changed

src/practice/1-2-dijkstra-shortest-path.ts

Lines changed: 58 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
import { IGraph } from './0-undirected-graph';
2-
2+
3+
const infinity = Number.POSITIVE_INFINITY;
4+
5+
export type DistanceEntry = {
6+
from: string | null,
7+
distance: number,
8+
};
9+
10+
export type DistanceToList = {
11+
[ dest: string ]: DistanceEntry,
12+
};
13+
314
export interface IPath {
415
nodeList: string[];
516
distance: number;
@@ -10,60 +21,77 @@ export function dijkstraShortestPath(
1021
sourceNode: string,
1122
destinationNode: string,
1223
): IPath {
13-
const edges = new Set(graph.edges);
14-
const distanceTo = graph.nodes
15-
.reduce(
16-
(result, node) => (
17-
result[node] = {
18-
from: null,
19-
distance: node === sourceNode ? 0 : Number.MAX_SAFE_INTEGER,
20-
},
21-
result
22-
),
23-
{} as { [ dest: string ]: { from: string | null, distance: number } }
24-
);
25-
26-
const unvisited = new Set(graph.nodes);
24+
const unvisitedNodes = new Set(graph.nodes);
25+
const unvisitedEdges = new Set(graph.edges);
26+
const distanceTo = initializeDistances(graph.nodes, sourceNode);
2727

2828
let currentNode: string | undefined = sourceNode;
2929
do {
30-
unvisited.delete(currentNode);
30+
unvisitedNodes.delete(currentNode);
3131

32-
for (let edge of edges)
32+
for (const edge of unvisitedEdges)
3333
if (edge.source === currentNode || edge.destination === currentNode) {
34-
edges.delete(edge);
34+
unvisitedEdges.delete(edge);
3535

36-
const neighbor = edge.source === currentNode ? edge.destination : edge.source;
36+
const neighborNode = edge.source === currentNode ? edge.destination : edge.source;
3737
const alternativeDistance = distanceTo[currentNode].distance + edge.distance;
3838

39-
if (alternativeDistance < distanceTo[neighbor].distance) {
40-
distanceTo[neighbor] = { from: currentNode, distance: alternativeDistance };
39+
if (alternativeDistance < distanceTo[neighborNode].distance) {
40+
distanceTo[neighborNode] = { from: currentNode, distance: alternativeDistance };
4141
}
4242
}
4343

44-
// current = unvisited node with shortest `distance` path to it
45-
let closestUnvisitedEntry = (Object
46-
.entries(distanceTo)
47-
.sort((entry1, entry2) => entry1["1"].distance - entry2["1"].distance)
48-
.find(entry => unvisited.has(entry["0"])));
49-
currentNode = closestUnvisitedEntry && closestUnvisitedEntry["0"];
50-
44+
currentNode = closestUnvisitedEntry(distanceTo, unvisitedNodes);
5145
} while (currentNode);
5246

5347
return {
5448
distance: distanceTo[destinationNode].distance,
5549
nodeList: unwindPath(distanceTo, destinationNode),
5650
};
5751
}
52+
53+
export function initializeDistances(
54+
nodes: string[],
55+
sourceNode: string,
56+
): DistanceToList {
57+
return nodes
58+
.reduce(
59+
(result, node) => (
60+
result[node] = {
61+
from: null,
62+
distance: node === sourceNode ? 0 : infinity,
63+
},
64+
result
65+
),
66+
{} as DistanceToList,
67+
);
68+
}
69+
70+
export function closestUnvisitedEntry(
71+
distanceTo: DistanceToList,
72+
unvisitedNodes: Set<string>,
73+
): string | undefined {
74+
let resultNode;
75+
let minimalDistance = infinity;
76+
for (const node of Object.keys(distanceTo)) {
77+
const nodeDistance = distanceTo[node].distance;
78+
if (unvisitedNodes.has(node) && nodeDistance < minimalDistance)
79+
{
80+
resultNode = node;
81+
minimalDistance = nodeDistance;
82+
}
83+
}
84+
return resultNode;
85+
}
5886

5987
export function unwindPath(
60-
distanceTo: { [dest: string]: { from: string | null, distance: number } },
88+
distanceTo: DistanceToList,
6189
destinationNode: string,
6290
) {
6391
const path: string[] = [ destinationNode ];
6492
let currentNode: string | null = destinationNode;
6593
do {
66-
const entry: { from: string | null, distance: number } = distanceTo[currentNode];
94+
const entry: DistanceEntry = distanceTo[currentNode];
6795
currentNode = entry.from;
6896
if (currentNode) path.unshift(currentNode);
6997
} while (currentNode);

0 commit comments

Comments
 (0)