dijkstra.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. 'use strict';
  2. /******************************************************************************
  3. * Created 2008-08-19.
  4. *
  5. * Dijkstra path-finding functions. Adapted from the Dijkstar Python project.
  6. *
  7. * Copyright (C) 2008
  8. * Wyatt Baldwin <self@wyattbaldwin.com>
  9. * All rights reserved
  10. *
  11. * Licensed under the MIT license.
  12. *
  13. * http://www.opensource.org/licenses/mit-license.php
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. * THE SOFTWARE.
  22. *****************************************************************************/
  23. var dijkstra = {
  24. single_source_shortest_paths: function(graph, s, d) {
  25. // Predecessor map for each node that has been encountered.
  26. // node ID => predecessor node ID
  27. var predecessors = {};
  28. // Costs of shortest paths from s to all nodes encountered.
  29. // node ID => cost
  30. var costs = {};
  31. costs[s] = 0;
  32. // Costs of shortest paths from s to all nodes encountered; differs from
  33. // `costs` in that it provides easy access to the node that currently has
  34. // the known shortest path from s.
  35. // XXX: Do we actually need both `costs` and `open`?
  36. var open = dijkstra.PriorityQueue.make();
  37. open.push(s, 0);
  38. var closest,
  39. u, v,
  40. cost_of_s_to_u,
  41. adjacent_nodes,
  42. cost_of_e,
  43. cost_of_s_to_u_plus_cost_of_e,
  44. cost_of_s_to_v,
  45. first_visit;
  46. while (!open.empty()) {
  47. // In the nodes remaining in graph that have a known cost from s,
  48. // find the node, u, that currently has the shortest path from s.
  49. closest = open.pop();
  50. u = closest.value;
  51. cost_of_s_to_u = closest.cost;
  52. // Get nodes adjacent to u...
  53. adjacent_nodes = graph[u] || {};
  54. // ...and explore the edges that connect u to those nodes, updating
  55. // the cost of the shortest paths to any or all of those nodes as
  56. // necessary. v is the node across the current edge from u.
  57. for (v in adjacent_nodes) {
  58. if (adjacent_nodes.hasOwnProperty(v)) {
  59. // Get the cost of the edge running from u to v.
  60. cost_of_e = adjacent_nodes[v];
  61. // Cost of s to u plus the cost of u to v across e--this is *a*
  62. // cost from s to v that may or may not be less than the current
  63. // known cost to v.
  64. cost_of_s_to_u_plus_cost_of_e = cost_of_s_to_u + cost_of_e;
  65. // If we haven't visited v yet OR if the current known cost from s to
  66. // v is greater than the new cost we just found (cost of s to u plus
  67. // cost of u to v across e), update v's cost in the cost list and
  68. // update v's predecessor in the predecessor list (it's now u).
  69. cost_of_s_to_v = costs[v];
  70. first_visit = (typeof costs[v] === 'undefined');
  71. if (first_visit || cost_of_s_to_v > cost_of_s_to_u_plus_cost_of_e) {
  72. costs[v] = cost_of_s_to_u_plus_cost_of_e;
  73. open.push(v, cost_of_s_to_u_plus_cost_of_e);
  74. predecessors[v] = u;
  75. }
  76. }
  77. }
  78. }
  79. if (typeof d !== 'undefined' && typeof costs[d] === 'undefined') {
  80. var msg = ['Could not find a path from ', s, ' to ', d, '.'].join('');
  81. throw new Error(msg);
  82. }
  83. return predecessors;
  84. },
  85. extract_shortest_path_from_predecessor_list: function(predecessors, d) {
  86. var nodes = [];
  87. var u = d;
  88. var predecessor;
  89. while (u) {
  90. nodes.push(u);
  91. predecessor = predecessors[u];
  92. u = predecessors[u];
  93. }
  94. nodes.reverse();
  95. return nodes;
  96. },
  97. find_path: function(graph, s, d) {
  98. var predecessors = dijkstra.single_source_shortest_paths(graph, s, d);
  99. return dijkstra.extract_shortest_path_from_predecessor_list(
  100. predecessors, d);
  101. },
  102. /**
  103. * A very naive priority queue implementation.
  104. */
  105. PriorityQueue: {
  106. make: function (opts) {
  107. var T = dijkstra.PriorityQueue,
  108. t = {},
  109. key;
  110. opts = opts || {};
  111. for (key in T) {
  112. if (T.hasOwnProperty(key)) {
  113. t[key] = T[key];
  114. }
  115. }
  116. t.queue = [];
  117. t.sorter = opts.sorter || T.default_sorter;
  118. return t;
  119. },
  120. default_sorter: function (a, b) {
  121. return a.cost - b.cost;
  122. },
  123. /**
  124. * Add a new item to the queue and ensure the highest priority element
  125. * is at the front of the queue.
  126. */
  127. push: function (value, cost) {
  128. var item = {value: value, cost: cost};
  129. this.queue.push(item);
  130. this.queue.sort(this.sorter);
  131. },
  132. /**
  133. * Return the highest priority element in the queue.
  134. */
  135. pop: function () {
  136. return this.queue.shift();
  137. },
  138. empty: function () {
  139. return this.queue.length === 0;
  140. }
  141. }
  142. };
  143. // node.js module exports
  144. if (typeof module !== 'undefined') {
  145. module.exports = dijkstra;
  146. }