import 'package:collection/collection.dart'; class Edge { final double cost; final T destination; Edge(this.cost, this.destination); } class Result { final double cost; final T? predecessor; final T item; Result(this.cost, this.predecessor, this.item); } Iterable> dijkstra( T source, Iterable> Function(T) neighbors) sync* { var queue = PriorityQueue>((i0, i1) => i0.cost.compareTo(i1.cost)); Set 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? dijkstraPath( T source, T destination, Iterable> Function(T) neighbors, {double? maxCost}) { if (source == destination) { return []; } Map 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); } } }