@thi.ng/heaps
Version:
Various heap implementations for arbitrary values and with customizable ordering
148 lines (147 loc) • 3.09 kB
JavaScript
import { compare } from "@thi.ng/compare/compare";
import { equiv } from "@thi.ng/equiv";
const defPairingHeap = (values, opts) => new PairingHeap(values, opts);
class PairingHeap {
compare;
equiv;
root;
_size;
constructor(vals, opts) {
opts = { compare, equiv, ...opts };
this.compare = opts.compare;
this.equiv = opts.equiv;
this.clear();
vals && this.into(vals);
}
get length() {
return this._size;
}
*[Symbol.iterator]() {
const acc = [];
this.visit((x) => (acc.push(x), true));
yield* acc;
}
clear() {
this.root = { v: void 0, p: void 0, c: [] };
this._size = 0;
}
empty() {
return new PairingHeap(null, { compare, equiv });
}
copy() {
const heap = this.empty();
return heap;
}
push(v) {
this.root = this.merge(this.root, {
v,
p: void 0,
c: []
});
this._size++;
return this;
}
pop() {
const res = this.root.v;
if (res !== void 0) {
const children = this.root.c;
if (children.length) {
this.root = this.mergePairs(children);
} else {
this.root.v = void 0;
}
this._size--;
}
return res;
}
pushPop(x) {
if (!this._size || this.compare(x, this.root.v) < 0) {
return x;
}
const res = this.pop();
this.push(x);
return res;
}
peek() {
return this._size ? this.root.v : void 0;
}
into(vals) {
for (let i of vals) {
this.push(i);
}
return this;
}
find(val) {
let found;
this.visit((x) => this.equiv(x, val) ? (found = x, false) : true);
return found;
}
findWith(fn) {
let found;
this.visit((x) => fn(x) ? (found = x, false) : true);
return found;
}
has(val) {
return this.find(val) !== void 0;
}
/**
* Computes union with given heap and clears `heap`, i.e. this heap
* will take ownership of `heap`'s items (if any).
*
* @param heap -
*/
meld(heap) {
if (!heap._size) return this;
if (!this._size) {
this.root = heap.root;
this._size = heap._size;
} else {
this._size += heap._size;
this.root = this.compare(this.peek(), heap.peek()) <= 0 ? this.merge(this.root, heap.root) : this.merge(heap.root, this.root);
}
heap.clear();
return this;
}
visit(fn) {
this._size && this.doVisit(fn, this.root);
}
doVisit(fn, root) {
if (fn(root.v)) {
const children = root.c;
let ok = true;
for (let i = children.length; ok && i-- > 0; ) {
ok = this.doVisit(fn, children[i]);
}
return ok;
}
return false;
}
merge(a, b) {
if (a.v === void 0) {
return b;
}
if (this.compare(a.v, b.v) < 0) {
a.c.push(b);
b.p = a;
return a;
}
b.c.push(a);
a.p = b;
return b;
}
mergePairs(heaps) {
const n = heaps.length - 1;
let root = heaps[n];
if (n > 0) {
for (let i = n; i-- > 0; ) {
root = this.merge(root, heaps[i]);
}
}
root.p = void 0;
return root;
}
}
export {
PairingHeap,
defPairingHeap
};