1
1
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
+
3
14
export interface IPath {
4
15
nodeList : string [ ] ;
5
16
distance : number ;
@@ -10,60 +21,77 @@ export function dijkstraShortestPath(
10
21
sourceNode : string ,
11
22
destinationNode : string ,
12
23
) : 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 ) ;
27
27
28
28
let currentNode : string | undefined = sourceNode ;
29
29
do {
30
- unvisited . delete ( currentNode ) ;
30
+ unvisitedNodes . delete ( currentNode ) ;
31
31
32
- for ( let edge of edges )
32
+ for ( const edge of unvisitedEdges )
33
33
if ( edge . source === currentNode || edge . destination === currentNode ) {
34
- edges . delete ( edge ) ;
34
+ unvisitedEdges . delete ( edge ) ;
35
35
36
- const neighbor = edge . source === currentNode ? edge . destination : edge . source ;
36
+ const neighborNode = edge . source === currentNode ? edge . destination : edge . source ;
37
37
const alternativeDistance = distanceTo [ currentNode ] . distance + edge . distance ;
38
38
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 } ;
41
41
}
42
42
}
43
43
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 ) ;
51
45
} while ( currentNode ) ;
52
46
53
47
return {
54
48
distance : distanceTo [ destinationNode ] . distance ,
55
49
nodeList : unwindPath ( distanceTo , destinationNode ) ,
56
50
} ;
57
51
}
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
+ }
58
86
59
87
export function unwindPath (
60
- distanceTo : { [ dest : string ] : { from : string | null , distance : number } } ,
88
+ distanceTo : DistanceToList ,
61
89
destinationNode : string ,
62
90
) {
63
91
const path : string [ ] = [ destinationNode ] ;
64
92
let currentNode : string | null = destinationNode ;
65
93
do {
66
- const entry : { from : string | null , distance : number } = distanceTo [ currentNode ] ;
94
+ const entry : DistanceEntry = distanceTo [ currentNode ] ;
67
95
currentNode = entry . from ;
68
96
if ( currentNode ) path . unshift ( currentNode ) ;
69
97
} while ( currentNode ) ;
0 commit comments