55 lines
1.3 KiB
JavaScript
55 lines
1.3 KiB
JavaScript
const _ = require('../lodash')
|
|
const PriorityQueue = require('../data/priority-queue')
|
|
|
|
module.exports = dijkstra
|
|
|
|
var DEFAULT_WEIGHT_FUNC = _.constant(1)
|
|
|
|
function dijkstra (g, source, weightFn, edgeFn) {
|
|
return runDijkstra(g, String(source),
|
|
weightFn || DEFAULT_WEIGHT_FUNC,
|
|
edgeFn || function (v) { return g.outEdges(v) })
|
|
}
|
|
|
|
function runDijkstra (g, source, weightFn, edgeFn) {
|
|
const results = {}
|
|
const pq = new PriorityQueue()
|
|
let v, vEntry
|
|
|
|
var updateNeighbors = function (edge) {
|
|
const w = edge.v !== v ? edge.v : edge.w
|
|
const wEntry = results[w]
|
|
const weight = weightFn(edge)
|
|
const distance = vEntry.distance + weight
|
|
|
|
if (weight < 0) {
|
|
throw new Error('dijkstra does not allow negative edge weights. ' +
|
|
'Bad edge: ' + edge + ' Weight: ' + weight)
|
|
}
|
|
|
|
if (distance < wEntry.distance) {
|
|
wEntry.distance = distance
|
|
wEntry.predecessor = v
|
|
pq.decrease(w, distance)
|
|
}
|
|
}
|
|
|
|
g.nodes().forEach(function (v) {
|
|
var distance = v === source ? 0 : Number.POSITIVE_INFINITY
|
|
results[v] = { distance: distance }
|
|
pq.add(v, distance)
|
|
})
|
|
|
|
while (pq.size() > 0) {
|
|
v = pq.removeMin()
|
|
vEntry = results[v]
|
|
if (vEntry.distance === Number.POSITIVE_INFINITY) {
|
|
break
|
|
}
|
|
|
|
edgeFn(v).forEach(updateNeighbors)
|
|
}
|
|
|
|
return results
|
|
}
|