dartterm/lib/algorithms/dijkstra.dart
2023-09-22 21:08:03 -07:00

73 lines
1.6 KiB
Dart

import 'package:collection/collection.dart';
class Edge<T> {
final double cost;
final T destination;
Edge(this.cost, this.destination);
}
class Result<T> {
final double cost;
final T? predecessor;
final T item;
Result(this.cost, this.predecessor, this.item);
}
Iterable<Result<T>> dijkstra<T>(
T source, Iterable<Edge<T>> Function(T) neighbors) sync* {
var queue = PriorityQueue<Result<T>>((i0, i1) => i0.cost.compareTo(i1.cost));
Set<T> seen = {source};
queue.add(Result(0.0, null, source));
while (queue.isNotEmpty) {
var u = queue.removeFirst();
yield u;
for (var v in neighbors(u.item)) {
if (seen.contains(v.destination)) {
continue;
}
seen.add(v.destination);
queue.add(Result(u.cost + v.cost, u.item, v.destination));
}
}
}
List<T>? dijkstraPath<T>(
T source, T destination, Iterable<Edge<T>> Function(T) neighbors,
{double? maxCost}) {
if (source == destination) {
return [];
}
Map<T, T?> predecessor = {};
for (var r in dijkstra(source, neighbors)) {
predecessor[r.item] = r.predecessor;
if (maxCost != null && r.cost >= maxCost) {
return null;
}
if (r.item == destination) {
break;
}
}
var revPath = [destination];
while (true) {
var pred = predecessor[revPath.last];
if (pred == source) {
revPath.reverseRange(0, revPath.length);
return revPath;
} else if (pred == null) {
throw Exception(
"predecessor should not be null -- that would mean we missed source");
} else {
revPath.add(pred);
}
}
}