Skip to content

Commit bf23c4a

Browse files
committed
inner loop micro optimization
1 parent d0a2045 commit bf23c4a

File tree

2 files changed

+38
-18
lines changed

2 files changed

+38
-18
lines changed

README.md

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,46 @@
22

33
A pretty good implementation of Dijkstra's shortest-path algorithm for Deno.
44

5-
If you ever run into a problem that can be represented as a graph where the solution has something to do with finding the shortest path between nodes, this algorithm is nothing short of magical. It is well worth the time to learn how to use it, even if you don't really understand how the algorithm works.
5+
If you ever run into a problem that can be represented as a graph where the
6+
solution has something to do with finding the shortest path between nodes, this
7+
algorithm is nothing short of magical. It is well worth the time to learn how to
8+
use it, even if you don't really understand how the algorithm works.
69

7-
This implementation of Dijkstra'a algorithm is able to process large in-memory graphs. It will perform
8-
reasonably well even when the number of edges is in the millions. The performance is `O(n*log(n))`, where `n` is proportional to the number of nodes plus the number of edges in the graph.
10+
This implementation of Dijkstra'a algorithm is able to process large in-memory
11+
graphs. It will perform reasonably well even when the number of edges is in the
12+
millions. The performance is `O(n*log(n))`, where `n` is proportional to the
13+
number of nodes plus the number of edges in the graph.
914

1015
This code was adapted to Typescript from
1116
[A Walkthrough of Dijkstra's Algorithm (In JavaScript!)](https://medium.com/@adriennetjohnson/a-walkthrough-of-dijkstras-algorithm-in-javascript-e94b74192026)
1217
on Medium. This implemetation was originally part of
1318
[BlackholeSuns](https://github.com/j50n/blackholesuns), an open source project
1419
that allowed thousands of No Man's Sky players to navigate the galaxy using
15-
mapped black holes. This version is cleaned up a bit and includes a few bug fixes and more tests than the original. See also
20+
mapped black holes. This version is cleaned up a bit and includes a few bug
21+
fixes and more tests than the original. See also
1622
[Dijkstra's algorithm](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm) on
1723
Wikipedia.
1824

1925
# Usage Hints
2026

21-
Dijkstra's algorithm actually calculates the shortest paths from the start node to every other node in the graph. In other words, it isn't just calculating one path at a time. This can let you cheaply do things like find the 20 closest nodes from a particular node in the graph, for example.
27+
Dijkstra's algorithm actually calculates the shortest paths from the start node
28+
to every other node in the graph. In other words, it isn't just calculating one
29+
path at a time. This can let you cheaply do things like find the 20 closest
30+
nodes from a particular node in the graph, for example.
2231

23-
You can reverse the direction of the calculation. Calling it "start node" is just a convention. It can also be an end node if you set up the graph correctly.
32+
You can reverse the direction of the calculation. Calling it "start node" is
33+
just a convention. It can also be an end node if you set up the graph correctly.
2434

25-
This implementation supports cloning the solver and extending its graph dynamically. Graph generation can be expensive. For many cases, most of the graph can be reused, with a only a small portion needing to be dynamic.
35+
This implementation supports cloning the solver and extending its graph
36+
dynamically. Graph generation can be expensive. For many cases, most of the
37+
graph can be reused, with a only a small portion needing to be dynamic.
2638

2739
# Example
2840

2941
This example recreates the example from the article referenced earlier. The
3042
nodes are mapped to integers from `0` to `n-1`. The names and weights are taken
31-
from [A Walkthrough of Dijkstra's Algorithm (In JavaScript!)](https://medium.com/@adriennetjohnson/a-walkthrough-of-dijkstras-algorithm-in-javascript-e94b74192026).
43+
from
44+
[A Walkthrough of Dijkstra's Algorithm (In JavaScript!)](https://medium.com/@adriennetjohnson/a-walkthrough-of-dijkstras-algorithm-in-javascript-e94b74192026).
3245

3346
```ts
3447
const FULLSTACK = 0;

dijkstra.ts

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export class DijkstraShortestPathSolver {
6868
}
6969

7070
/**
71-
* The number of nodes in the graph.
71+
* The number of nodes in the graph. Nodes are numbered from `0` to `n-1`.
7272
*/
7373
protected get nodes(): number {
7474
return this.adjacencyList.length;
@@ -144,15 +144,22 @@ export class DijkstraShortestPathSolver {
144144
this.adjacencyList[toNode].push({ toNode: fromNode, weight });
145145
}
146146

147-
setEdges(node: number, edges: IEdge[]): void {
148-
this.adjacencyList[node] = edges;
149-
}
147+
// TODO: Not ready for general consumption.
148+
// setEdges(node: number, edges: IEdge[]): void {
149+
// this.adjacencyList[node] = edges;
150+
// }
150151

151152
/**
152153
* Calculate shortest paths for all nodes for the given start node.
153154
* @param startNode The start node.
154155
*/
155156
calculateFor(startNode: number): ShortestPaths {
157+
if (startNode < 0 || startNode >= this.nodes) {
158+
throw new RangeError(
159+
`startNode must be in range 0..${this.nodes - 1}: ${startNode}`,
160+
);
161+
}
162+
156163
const weights: number[] = new Array(this.nodes).fill(Infinity);
157164
weights[startNode] = 0;
158165

@@ -166,15 +173,15 @@ export class DijkstraShortestPathSolver {
166173
while (pq.length !== 0) {
167174
const shortestStep = pq.pop();
168175

169-
const currentNode = shortestStep!.toNode;
176+
const currentNode: number = shortestStep!.toNode;
170177

171178
for (const neighbor of this.adjacencyList[currentNode]) {
172179
const weight = weights[currentNode] + neighbor.weight;
173-
174-
if (weight < weights[neighbor.toNode]) {
175-
weights[neighbor.toNode] = weight;
176-
backtrace[neighbor.toNode] = currentNode;
177-
pq.push({ toNode: neighbor.toNode, weight: weight });
180+
const toNode = neighbor.toNode;
181+
if (weight < weights[toNode]) {
182+
weights[toNode] = weight;
183+
backtrace[toNode] = currentNode;
184+
pq.push({ toNode, weight });
178185
}
179186
}
180187
}

0 commit comments

Comments
 (0)