UNPKG

@thi.ng/heaps

Version:

Various heap implementations for arbitrary values and with customizable ordering

148 lines (147 loc) 3.09 kB
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 };