Fix: heap sift-down to the right happened even when it shouldn't have

master
Dany Thach 2025-02-15 19:40:47 +01:00
parent 0b88775b0c
commit a22d229c01
1 changed files with 36 additions and 17 deletions

View File

@ -3,14 +3,14 @@ class SearchHeap<K, T> {
final K Function(T) getKey; final K Function(T) getKey;
final int Function(T) getPriority; final int Function(T) getPriority;
List<(T, K, int)> _items; List<(T, K, int)> _items;
Map<K, int> _positionByKey; Map<K, int> _indexByKey;
SearchHeap({ SearchHeap({
required this.getKey, required this.getKey,
required this.getPriority, required this.getPriority,
}): }):
_items = [], _items = [],
_positionByKey = {}; _indexByKey = {};
factory SearchHeap.fromItems( factory SearchHeap.fromItems(
List<T> items, List<T> items,
@ -43,11 +43,11 @@ class SearchHeap<K, T> {
_items.add(heapItem); _items.add(heapItem);
while (i > 0 && _items[(i-1) >> 1].$3 > thisKey) { while (i > 0 && _items[(i-1) >> 1].$3 > thisKey) {
_items[i] = _items[(i-1) >> 1]; _items[i] = _items[(i-1) >> 1];
_positionByKey[_items[i].$2] = i; _indexByKey[_items[i].$2] = i;
i = (i-1) >> 1; i = (i-1) >> 1;
} }
_items[i] = heapItem; _items[i] = heapItem;
_positionByKey[heapItem.$2] = i; _indexByKey[heapItem.$2] = i;
} }
T removeFirst() { T removeFirst() {
@ -55,7 +55,7 @@ class SearchHeap<K, T> {
throw StateError("No element"); throw StateError("No element");
} }
final T firstItem = _items[0].$1; final T firstItem = _items[0].$1;
_positionByKey.remove(_items[0].$2); _indexByKey.remove(_items[0].$2);
if (_items.length < 2) { if (_items.length < 2) {
_items.length--; _items.length--;
return firstItem; return firstItem;
@ -71,34 +71,34 @@ class SearchHeap<K, T> {
if (leftIndex < _items.length && itemToMove.$3 > _items[leftIndex].$3) { if (leftIndex < _items.length && itemToMove.$3 > _items[leftIndex].$3) {
if (rightIndex < _items.length && _items[leftIndex].$3 > _items[rightIndex].$3) { if (rightIndex < _items.length && _items[leftIndex].$3 > _items[rightIndex].$3) {
_items[i] = _items[rightIndex]; _items[i] = _items[rightIndex];
_positionByKey[_items[i].$2] = i; _indexByKey[_items[i].$2] = i;
i = rightIndex; i = rightIndex;
} else { } else {
_items[i] = _items[leftIndex]; _items[i] = _items[leftIndex];
_positionByKey[_items[i].$2] = i; _indexByKey[_items[i].$2] = i;
i = leftIndex; i = leftIndex;
} }
} else if (rightIndex < _items.length && _items[leftIndex].$3 > _items[rightIndex].$3) { } else if (rightIndex < _items.length && itemToMove.$3 > _items[rightIndex].$3) {
_items[i] = _items[rightIndex]; _items[i] = _items[rightIndex];
_positionByKey[_items[i].$2] = i; _indexByKey[_items[i].$2] = i;
i = rightIndex; i = rightIndex;
} else { } else {
stop = true; stop = true;
} }
} }
_items[i] = itemToMove; _items[i] = itemToMove;
_positionByKey[itemToMove.$2] = i; _indexByKey[itemToMove.$2] = i;
return firstItem; return firstItem;
} }
void updateElement(K key) { void updateElement(K key) {
int i = _positionByKey[key]!; int i = _indexByKey[key]!;
final (T, K, int) item = (_items[i].$1, _items[i].$2, getPriority(_items[i].$1)); final (T, K, int) item = (_items[i].$1, _items[i].$2, getPriority(_items[i].$1));
bool dontBubbleDown = false; bool dontBubbleDown = false;
while (i > 0 && _items[(i-1) >> 1].$3 > item.$3) { while (i > 0 && _items[(i-1) >> 1].$3 > item.$3) {
dontBubbleDown = true; dontBubbleDown = true;
_items[i] = _items[(i-1) >> 1]; _items[i] = _items[(i-1) >> 1];
_positionByKey[_items[i].$2] = i; _indexByKey[_items[i].$2] = i;
i = (i-1) >> 1; i = (i-1) >> 1;
} }
int leftIndex, rightIndex; int leftIndex, rightIndex;
@ -108,28 +108,47 @@ class SearchHeap<K, T> {
if (leftIndex < _items.length && item.$3 > _items[leftIndex].$3) { if (leftIndex < _items.length && item.$3 > _items[leftIndex].$3) {
if (rightIndex < _items.length && _items[leftIndex].$3 > _items[rightIndex].$3) { if (rightIndex < _items.length && _items[leftIndex].$3 > _items[rightIndex].$3) {
_items[i] = _items[rightIndex]; _items[i] = _items[rightIndex];
_positionByKey[_items[i].$2] = i; _indexByKey[_items[i].$2] = i;
i = rightIndex; i = rightIndex;
} else { } else {
_items[i] = _items[leftIndex]; _items[i] = _items[leftIndex];
_positionByKey[_items[i].$2] = i; _indexByKey[_items[i].$2] = i;
i = leftIndex; i = leftIndex;
} }
} else if (rightIndex < _items.length && _items[leftIndex].$3 > _items[rightIndex].$3) { } else if (rightIndex < _items.length && item.$3 > _items[rightIndex].$3) {
_items[i] = _items[rightIndex]; _items[i] = _items[rightIndex];
_positionByKey[_items[i].$2] = i; _indexByKey[_items[i].$2] = i;
i = rightIndex; i = rightIndex;
} else { } else {
dontBubbleDown = true; dontBubbleDown = true;
} }
} }
_items[i] = item; _items[i] = item;
_positionByKey[item.$2] = i; _indexByKey[item.$2] = i;
} }
@override @override
String toString() => _items.map(((T, K, int) item) => item.$1).toString(); String toString() => _items.map(((T, K, int) item) => item.$1).toString();
List<T> get debugItems => _items.map(((T, K, int) item) => item.$1).toList(); List<T> get debugItems => _items.map(((T, K, int) item) => item.$1).toList();
Map<K, int> get debugPositionByKey => _indexByKey;
bool get debugHeapValidity {
for (int i = 1; i < _items.length; i++) {
if (_items[i].$3 < _items[(i-1) >> 1].$3) {
return false;
}
}
return true;
}
bool get debugDictionaryValidity {
for (final MapEntry<K, int>(key: K key, value: int index) in _indexByKey.entries) {
if (_items[index].$2 != key) {
return false;
}
}
return true;
}
} }