class Heap { final int Function(T) getPriority; List<(T, int)> _items; Heap({ required this.getPriority }): _items = []; factory Heap.fromItems( List items, { required int Function(T) getPriority, } ) { Heap heap = Heap(getPriority: getPriority); for (final T item in items) { heap.add(item); } return heap; } T get first => _items.first.$1; T? get firstOrNull => _items.firstOrNull?.$1; int get length => _items.length; bool get isEmpty => _items.isEmpty; bool get isNotEmpty => _items.isNotEmpty; void add(T item) { final (T, int) heapItem = (item, getPriority(item)); final int thisKey = heapItem.$2; int i = _items.length; _items.add(heapItem); while (i > 0 && _items[(i-1) ~/ 2].$2 > thisKey) { _items[i] = _items[(i-1) ~/ 2]; i = (i-1)~/2; } _items[i] = heapItem; } T removeFirst() { if (_items.isEmpty) { throw StateError("No element"); } final T firstItem = _items[0].$1; if (_items.length < 2) { _items.length--; return firstItem; } final (T, int) itemToMove = _items.last; _items[0] = itemToMove; _items.length--; int i = 0; int leftIndex, rightIndex; bool stop = false; while (!stop) { rightIndex = (i+1) << 1; leftIndex = rightIndex-1; if (leftIndex < _items.length && itemToMove.$2 > _items[leftIndex].$2) { if (rightIndex < _items.length && _items[leftIndex].$2 > _items[rightIndex].$2) { _items[i] = _items[rightIndex]; _items[rightIndex] = itemToMove; i = rightIndex; } else { _items[i] = _items[leftIndex]; _items[leftIndex] = itemToMove; i = leftIndex; } } else { stop = true; } } return firstItem; } @override String toString() => _items.map(((T, int) item) => item.$1).toString(); }