55 lines
		
	
	
		
			1.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			55 lines
		
	
	
		
			1.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| var _ = require("../lodash");
 | |
| var 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) {
 | |
|   var results = {};
 | |
|   var pq = new PriorityQueue();
 | |
|   var v, vEntry;
 | |
| 
 | |
|   var updateNeighbors = function(edge) {
 | |
|     var w = edge.v !== v ? edge.v : edge.w;
 | |
|     var wEntry = results[w];
 | |
|     var weight = weightFn(edge);
 | |
|     var 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;
 | |
| }
 |