UNPKG

@panyam/priorityq

Version:

A Priority Queue implementation with O(1) lookups for lookup by value.

176 lines 5.75 kB
import { Storage } from "./storage"; class BHPQHandle { constructor(value, index) { this.value = value; this.index = index; } } export class BinHeapStorage extends Storage { constructor() { super(...arguments); this.handles = []; this.count = 0; this.emptyIndexes = []; } get size() { return this.count; } get isEmpty() { return this.count == 0; } clear() { this.handles = []; this.emptyIndexes = []; this.count = 0; } adjust(handle) { let curr = handle.index; if (this.upheap(curr) == curr) { const size = this.handles.length; curr = handle.index; while (curr < size) { const left = 2 * curr + 1; const right = 2 * curr + 2; const leftPtr = left >= size ? null : this.handles[left]; const rightPtr = right >= size ? null : this.handles[right]; if (leftPtr == null && rightPtr == null) return; let smaller = -1; if (leftPtr == null && rightPtr != null) { smaller = right; } else if (rightPtr == null && leftPtr != null) { smaller = left; } else if (this.comparator(leftPtr.value, rightPtr.value) < 0) { smaller = left; } else { smaller = right; } if (this.comparator(handle.value, this.handles[smaller].value) < 0) return; this.handles[curr] = this.handles[smaller]; this.handles[curr].index = curr; this.handles[smaller] = handle; this.handles[smaller].index = smaller; curr = smaller; } } } get top() { if (this.handles[0] == null) { throw new Error("Storage is empty"); } return this.handles[0]; } push(value) { const handle = new BHPQHandle(value, this.count); this.count++; if (this.emptyIndexes.length > 0) { const i = this.emptyIndexes.pop(); handle.index = i; this.handles[i] = handle; } else { this.handles.push(handle); const newlen = this.count; const newcapacity = (newlen * 3) >> 1; const spare = Math.max(8, newcapacity - newlen); for (let i = 0; i < spare; i++) { this.handles.push(null); this.emptyIndexes.push(newlen + spare - 1 - i); } } this.upheap(handle.index); return handle; } pop() { if (this.handles[0] == null) { throw new Error("Storage is empty"); } return this.remove(this.handles[0]); } remove(handle) { const size = this.handles.length; let curr = handle.index; while (curr < size) { const left = 2 * curr + 1; const right = 2 * curr + 2; const leftPtr = left >= size ? null : this.handles[left]; const rightPtr = right >= size ? null : this.handles[right]; let which = -1; if (leftPtr == null && rightPtr != null) { which = right; } else if (rightPtr == null && leftPtr != null) { which = left; } else if (leftPtr == null && rightPtr == null) { break; } else { if (this.comparator(leftPtr.value, rightPtr.value) < 0) which = left; else which = right; } this.handles[curr] = this.handles[which]; this.handles[curr].index = curr; this.handles[which] = handle; this.handles[which].index = which; curr = which; } this.count--; this.handles[handle.index] = null; this.releaseIndex(handle.index); return handle; } get sortedHandles() { const out = this.handles.filter((x) => x != null); const cmpFunc = this.comparator; out.sort((x, y) => cmpFunc(x.value, y.value)); return out.values(); } upheap(curr) { const start = curr; let parentIsEmpty = false; while (curr > 0) { const parent = (curr - 1) >> 1; const parentHandle = this.handles[parent]; parentIsEmpty = parentHandle == null; if (parentHandle != null) { if (this.comparator(parentHandle.value, this.handles[curr].value) <= 0) break; parentHandle.index = curr; } this.handles[curr].index = parent; const temp = this.handles[parent]; this.handles[parent] = this.handles[curr]; this.handles[curr] = temp; curr = parent; } if (parentIsEmpty) this.releaseIndex(start); return curr; } releaseIndex(index) { const A = this.emptyIndexes; let lo = 0; let hi = A.length - 1; while (lo <= hi) { const mid = (lo + hi) >> 1; if (A[mid] == index) { throw new Error(`A[${mid}] (${A[mid]}) should not be equal to index (${index})`); } if (index < A[mid]) { lo = mid + 1; } else { hi = mid - 1; } } A.splice(lo, 0, index); } } //# sourceMappingURL=binheap.js.map