dijkstra.js 1.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  1. const _ = require('../lodash')
  2. const PriorityQueue = require('../data/priority-queue')
  3. module.exports = dijkstra
  4. var DEFAULT_WEIGHT_FUNC = _.constant(1)
  5. function dijkstra (g, source, weightFn, edgeFn) {
  6. return runDijkstra(g, String(source),
  7. weightFn || DEFAULT_WEIGHT_FUNC,
  8. edgeFn || function (v) { return g.outEdges(v) })
  9. }
  10. function runDijkstra (g, source, weightFn, edgeFn) {
  11. const results = {}
  12. const pq = new PriorityQueue()
  13. let v, vEntry
  14. var updateNeighbors = function (edge) {
  15. const w = edge.v !== v ? edge.v : edge.w
  16. const wEntry = results[w]
  17. const weight = weightFn(edge)
  18. const distance = vEntry.distance + weight
  19. if (weight < 0) {
  20. throw new Error('dijkstra does not allow negative edge weights. ' +
  21. 'Bad edge: ' + edge + ' Weight: ' + weight)
  22. }
  23. if (distance < wEntry.distance) {
  24. wEntry.distance = distance
  25. wEntry.predecessor = v
  26. pq.decrease(w, distance)
  27. }
  28. }
  29. g.nodes().forEach(function (v) {
  30. var distance = v === source ? 0 : Number.POSITIVE_INFINITY
  31. results[v] = { distance: distance }
  32. pq.add(v, distance)
  33. })
  34. while (pq.size() > 0) {
  35. v = pq.removeMin()
  36. vEntry = results[v]
  37. if (vEntry.distance === Number.POSITIVE_INFINITY) {
  38. break
  39. }
  40. edgeFn(v).forEach(updateNeighbors)
  41. }
  42. return results
  43. }