@panyam/priorityq
Version:
A Priority Queue implementation with O(1) lookups for lookup by value.
176 lines • 5.75 kB
JavaScript
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