Last active
November 26, 2023 09:34
-
-
Save earlonrails/f25ebd224ede7bc6338a839ec9469a53 to your computer and use it in GitHub Desktop.
shortest path and bfs in es6 javascript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env node | |
// Question found here: | |
// https://stackoverflow.com/questions/32527026/shortest-path-in-javascript | |
// Based on the first accepted answer | |
"use strict" | |
const expect = require('expect.js') | |
class Graph { | |
constructor(props) { | |
this.neighbors = {} | |
} | |
addEdge(u, v) { | |
if (!this.neighbors[u]) this.neighbors[u] = [] | |
this.neighbors[u].push(v) | |
} | |
bfs(start) { | |
if (!this.neighbors[start] || !this.neighbors[start].length) { | |
return [start] | |
} | |
var results = {"nodes": []}, | |
queue = this.neighbors[start], | |
count = 1 | |
while(queue.length) { | |
var node = queue.shift() | |
if (!results[node] || !results[node].visited) { | |
results[node] = {visited: true, steps: count} | |
results["nodes"].push(node) | |
if (this.neighbors[node]) { | |
if (this.neighbors[node].length) { | |
count++ | |
queue.push(...this.neighbors[node]) | |
} else { | |
continue | |
} | |
} | |
} | |
} | |
return results | |
} | |
shortestPath(start, end) { | |
if (start == end) { | |
return [start, end] | |
} | |
var queue = [start], | |
visited = {}, | |
predecessor = {}, | |
tail = 0, | |
path | |
while(tail < queue.length) { | |
var u = queue[tail++] | |
if (!this.neighbors[u]) { | |
continue | |
} | |
var neighbors = this.neighbors[u] | |
for(var i = 0; i < neighbors.length; ++i) { | |
var v = neighbors[i] | |
if (visited[v]) { | |
continue | |
} | |
visited[v] = true | |
if (v === end) { // Check if the path is complete. | |
path = [ v ] // If so, backtrack through the path. | |
while (u !== start) { | |
path.push(u) | |
u = predecessor[u] | |
} | |
path.push(u) | |
path.reverse() | |
return path | |
} | |
predecessor[v] = u | |
queue.push(v) | |
} | |
} | |
return path | |
} | |
} | |
// start -> [A]→[B]→[C]→[D] [E] | |
// ↓ ↑ ↓ | |
// [F]→[G]→[H] [I]→[J] | |
// ↓ ↓ ↓ | |
// [K]→[L]→[M] [N] [O] -> end | |
// ↓ ↓ ↑ | |
// [P]→[Q]→[R]→[S]→[T] | |
// Shortest Path 6 A→B→C→D→I→J→O | |
var createGraph = function() { | |
var g = new Graph() | |
g.addEdge('A', 'B') | |
g.addEdge('B', 'C') | |
g.addEdge('C', 'D') | |
g.addEdge('D', 'I') | |
g.addEdge('A', 'F') | |
g.addEdge('G', 'B') | |
g.addEdge('G', 'H') | |
g.addEdge('H', 'M') | |
g.addEdge('I', 'N') | |
g.addEdge('I', 'J') | |
g.addEdge('J', 'O') | |
g.addEdge('K', 'L') | |
g.addEdge('K', 'P') | |
g.addEdge('L', 'M') | |
g.addEdge('M', 'R') | |
g.addEdge('P', 'Q') | |
g.addEdge('Q', 'R') | |
g.addEdge('R', 'S') | |
g.addEdge('S', 'T') | |
g.addEdge('T', 'O') | |
return g | |
} | |
var bfsGraph = createGraph() | |
var bfsPath = bfsGraph.bfs('A') | |
expect(bfsPath).to.eql({ nodes: [ 'B', 'F', 'C', 'D', 'I', 'N', 'J', 'O' ], | |
B: { visited: true, steps: 1 }, | |
F: { visited: true, steps: 2 }, | |
C: { visited: true, steps: 2 }, | |
D: { visited: true, steps: 3 }, | |
I: { visited: true, steps: 4 }, | |
N: { visited: true, steps: 5 }, | |
J: { visited: true, steps: 5 }, | |
O: { visited: true, steps: 6 } }) | |
console.dir(bfsPath) | |
var shortestPathGraph = createGraph() | |
var path = shortestPathGraph.shortestPath('A', 'O') | |
expect(path).to.eql([ 'A', 'B', 'C', 'D', 'I', 'J', 'O']) | |
console.log(path.join('→')) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment