min-priority-queue-typed
Version:
Min Priority Queue
1,758 lines (1,199 loc) • 40.4 kB
JavaScript
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
// src/common/error.ts
function raise(ErrorClass, message) {
throw new ErrorClass(message);
}
__name(raise, "raise");
var ERR = {
// Range / index
indexOutOfRange: /* @__PURE__ */ __name((index, min, max, ctx) => `${ctx ? ctx + ": " : ""}Index ${index} is out of range [${min}, ${max}].`, "indexOutOfRange"),
invalidIndex: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Index must be an integer.`, "invalidIndex"),
// Type / argument
invalidArgument: /* @__PURE__ */ __name((reason, ctx) => `${ctx ? ctx + ": " : ""}${reason}`, "invalidArgument"),
comparatorRequired: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Comparator is required for non-number/non-string/non-Date keys.`, "comparatorRequired"),
invalidKey: /* @__PURE__ */ __name((reason, ctx) => `${ctx ? ctx + ": " : ""}${reason}`, "invalidKey"),
notAFunction: /* @__PURE__ */ __name((name, ctx) => `${ctx ? ctx + ": " : ""}${name} must be a function.`, "notAFunction"),
invalidEntry: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Each entry must be a [key, value] tuple.`, "invalidEntry"),
invalidNaN: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}NaN is not a valid key.`, "invalidNaN"),
invalidDate: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Invalid Date key.`, "invalidDate"),
reduceEmpty: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Reduce of empty structure with no initial value.`, "reduceEmpty"),
callbackReturnType: /* @__PURE__ */ __name((expected, got, ctx) => `${ctx ? ctx + ": " : ""}Callback must return ${expected}; got ${got}.`, "callbackReturnType"),
// State / operation
invalidOperation: /* @__PURE__ */ __name((reason, ctx) => `${ctx ? ctx + ": " : ""}${reason}`, "invalidOperation"),
// Matrix
matrixDimensionMismatch: /* @__PURE__ */ __name((op) => `Matrix: Dimensions must be compatible for ${op}.`, "matrixDimensionMismatch"),
matrixSingular: /* @__PURE__ */ __name(() => "Matrix: Singular matrix, inverse does not exist.", "matrixSingular"),
matrixNotSquare: /* @__PURE__ */ __name(() => "Matrix: Must be square for inversion.", "matrixNotSquare"),
matrixNotRectangular: /* @__PURE__ */ __name(() => "Matrix: Must be rectangular for transposition.", "matrixNotRectangular"),
matrixRowMismatch: /* @__PURE__ */ __name((expected, got) => `Matrix: Expected row length ${expected}, but got ${got}.`, "matrixRowMismatch"),
// Order statistic
orderStatisticNotEnabled: /* @__PURE__ */ __name((method, ctx) => `${ctx ? ctx + ": " : ""}${method}() requires enableOrderStatistic: true.`, "orderStatisticNotEnabled")
};
// src/common/index.ts
var DFSOperation = /* @__PURE__ */ ((DFSOperation2) => {
DFSOperation2[DFSOperation2["VISIT"] = 0] = "VISIT";
DFSOperation2[DFSOperation2["PROCESS"] = 1] = "PROCESS";
return DFSOperation2;
})(DFSOperation || {});
var Range = class {
constructor(low, high, includeLow = true, includeHigh = true) {
this.low = low;
this.high = high;
this.includeLow = includeLow;
this.includeHigh = includeHigh;
}
static {
__name(this, "Range");
}
// Determine whether a key is within the range
isInRange(key, comparator) {
const lowCheck = this.includeLow ? comparator(key, this.low) >= 0 : comparator(key, this.low) > 0;
const highCheck = this.includeHigh ? comparator(key, this.high) <= 0 : comparator(key, this.high) < 0;
return lowCheck && highCheck;
}
};
// src/data-structures/base/iterable-element-base.ts
var IterableElementBase = class {
static {
__name(this, "IterableElementBase");
}
/**
* Create a new iterable base.
*
* @param options Optional behavior overrides. When provided, a `toElementFn`
* is used to convert a raw element (`R`) into a public element (`E`).
*
* @remarks
* Time O(1), Space O(1).
*/
constructor(options) {
if (options) {
const { toElementFn } = options;
if (typeof toElementFn === "function") this._toElementFn = toElementFn;
else if (toElementFn) raise(TypeError, "toElementFn must be a function type");
}
}
/**
* The converter used to transform a raw element (`R`) into a public element (`E`).
*
* @remarks
* Time O(1), Space O(1).
*/
_toElementFn;
/**
* Exposes the current `toElementFn`, if configured.
*
* @returns The converter function or `undefined` when not set.
* @remarks
* Time O(1), Space O(1).
*/
get toElementFn() {
return this._toElementFn;
}
/**
* Returns an iterator over the structure's elements.
*
* @param args Optional iterator arguments forwarded to the internal iterator.
* @returns An `IterableIterator<E>` that yields the elements in traversal order.
*
* @remarks
* Producing the iterator is O(1); consuming the entire iterator is Time O(n) with O(1) extra space.
*/
*[Symbol.iterator](...args) {
yield* this._getIterator(...args);
}
/**
* Returns an iterator over the values (alias of the default iterator).
*
* @returns An `IterableIterator<E>` over all elements.
* @remarks
* Creating the iterator is O(1); full iteration is Time O(n), Space O(1).
*/
*values() {
for (const item of this) yield item;
}
/**
* Tests whether all elements satisfy the predicate.
*
* @template TReturn
* @param predicate Function invoked for each element with signature `(value, index, self)`.
* @param thisArg Optional `this` binding for the predicate.
* @returns `true` if every element passes; otherwise `false`.
*
* @remarks
* Time O(n) in the worst case; may exit early when the first failure is found. Space O(1).
*/
every(predicate, thisArg) {
let index = 0;
for (const item of this) {
if (thisArg === void 0) {
if (!predicate(item, index++, this)) return false;
} else {
const fn = predicate;
if (!fn.call(thisArg, item, index++, this)) return false;
}
}
return true;
}
/**
* Tests whether at least one element satisfies the predicate.
*
* @param predicate Function invoked for each element with signature `(value, index, self)`.
* @param thisArg Optional `this` binding for the predicate.
* @returns `true` if any element passes; otherwise `false`.
*
* @remarks
* Time O(n) in the worst case; may exit early on first success. Space O(1).
*/
some(predicate, thisArg) {
let index = 0;
for (const item of this) {
if (thisArg === void 0) {
if (predicate(item, index++, this)) return true;
} else {
const fn = predicate;
if (fn.call(thisArg, item, index++, this)) return true;
}
}
return false;
}
/**
* Invokes a callback for each element in iteration order.
*
* @param callbackfn Function invoked per element with signature `(value, index, self)`.
* @param thisArg Optional `this` binding for the callback.
* @returns `void`.
*
* @remarks
* Time O(n), Space O(1).
*/
forEach(callbackfn, thisArg) {
let index = 0;
for (const item of this) {
if (thisArg === void 0) {
callbackfn(item, index++, this);
} else {
const fn = callbackfn;
fn.call(thisArg, item, index++, this);
}
}
}
// Implementation signature
find(predicate, thisArg) {
let index = 0;
for (const item of this) {
if (thisArg === void 0) {
if (predicate(item, index++, this)) return item;
} else {
const fn = predicate;
if (fn.call(thisArg, item, index++, this)) return item;
}
}
return;
}
/**
* Checks whether a strictly-equal element exists in the structure.
*
* @param element The element to test with `===` equality.
* @returns `true` if an equal element is found; otherwise `false`.
*
* @remarks
* Time O(n) in the worst case. Space O(1).
*/
has(element) {
for (const ele of this) if (ele === element) return true;
return false;
}
/**
* Check whether a value exists (Array-compatible alias for `has`).
* @remarks Provided for familiarity when migrating from Array. Time O(n), Space O(1).
* @param element - Element to search for (uses `===`).
* @returns `true` if found.
*/
includes(element) {
return this.has(element);
}
/**
* Return an iterator of `[index, value]` pairs (Array-compatible).
* @remarks Provided for familiarity when migrating from Array. Time O(n), Space O(1) per step.
*/
*entries() {
let index = 0;
for (const value of this) {
yield [index++, value];
}
}
/**
* Return an iterator of numeric indices (Array-compatible).
* @remarks Provided for familiarity when migrating from Array. Time O(n), Space O(1) per step.
*/
*keys() {
let index = 0;
for (const _ of this) {
yield index++;
}
}
/**
* Reduces all elements to a single accumulated value.
*
* @overload
* @param callbackfn Reducer of signature `(acc, value, index, self) => nextAcc`. The first element is used as the initial accumulator.
* @returns The final accumulated value typed as `E`.
*
* @overload
* @param callbackfn Reducer of signature `(acc, value, index, self) => nextAcc`.
* @param initialValue The initial accumulator value of type `E`.
* @returns The final accumulated value typed as `E`.
*
* @overload
* @template U The accumulator type when it differs from `E`.
* @param callbackfn Reducer of signature `(acc: U, value, index, self) => U`.
* @param initialValue The initial accumulator value of type `U`.
* @returns The final accumulated value typed as `U`.
*
* @remarks
* Time O(n), Space O(1). Throws if called on an empty structure without `initialValue`.
*/
reduce(callbackfn, initialValue) {
let index = 0;
const iter = this[Symbol.iterator]();
let acc;
if (arguments.length >= 2) {
acc = initialValue;
} else {
const first = iter.next();
if (first.done) raise(TypeError, "Reduce of empty structure with no initial value");
acc = first.value;
index = 1;
}
for (const value of iter) {
acc = callbackfn(acc, value, index++, this);
}
return acc;
}
/**
* Materializes the elements into a new array.
*
* @returns A shallow array copy of the iteration order.
* @remarks
* Time O(n), Space O(n).
*/
toArray() {
return [...this];
}
/**
* Returns a representation of the structure suitable for quick visualization.
* Defaults to an array of elements; subclasses may override to provide richer visuals.
*
* @returns A visual representation (array by default).
* @remarks
* Time O(n), Space O(n).
*/
toVisual() {
return [...this];
}
/**
* Prints `toVisual()` to the console. Intended for quick debugging.
*
* @returns `void`.
* @remarks
* Time O(n) due to materialization, Space O(n) for the intermediate representation.
*/
print() {
console.log(this.toVisual());
}
};
// src/data-structures/heap/heap.ts
var Heap = class _Heap extends IterableElementBase {
static {
__name(this, "Heap");
}
_equals = Object.is;
/**
* Create a Heap and optionally bulk-insert elements.
* @remarks Time O(N), Space O(N)
* @param [elements] - Iterable of elements (or raw values if toElementFn is set).
* @param [options] - Options such as comparator and toElementFn.
* @returns New Heap instance.
*/
constructor(elements = [], options) {
super(options);
if (options) {
const { comparator } = options;
if (comparator) this._comparator = comparator;
}
this.addMany(elements);
}
_elements = [];
/**
* Get the backing array of the heap.
* @remarks Time O(1), Space O(1)
* @returns Internal elements array.
*/
get elements() {
return this._elements;
}
/**
* Get the number of elements.
* @remarks Time O(1), Space O(1)
* @returns Heap size.
* @example
* // Track heap capacity
* const heap = new Heap<number>();
* console.log(heap.size); // 0;
* heap.add(10);
* heap.add(20);
* console.log(heap.size); // 2;
* heap.poll();
* console.log(heap.size); // 1;
*/
get size() {
return this.elements.length;
}
/**
* Get the last leaf element.
* @remarks Time O(1), Space O(1)
* @returns Last element or undefined.
*/
get leaf() {
return this.elements[this.size - 1] ?? void 0;
}
/**
* Create a heap of the same class from an iterable.
* @remarks Time O(N), Space O(N)
* @template T
* @template R
* @template S
* @param [elements] - Iterable of elements or raw records.
* @param [options] - Heap options including comparator.
* @returns A new heap instance of this class.
*/
static from(elements, options) {
return new this(elements, options);
}
/**
* Build a Heap from an iterable in linear time given a comparator.
* @remarks Time O(N), Space O(N)
* @template EE
* @template RR
* @param elements - Iterable of elements.
* @param options - Heap options including comparator.
* @returns A new Heap built from elements.
*/
static heapify(elements, options) {
return new _Heap(elements, options);
}
/**
* Insert an element.
* @remarks Time O(log N) amortized, Space O(1)
* @param element - Element to insert.
* @returns True.
* @example
* // basic Heap creation and add operation
* // Create a min heap (default)
* const minHeap = new Heap([5, 3, 7, 1, 9, 2]);
*
* // Verify size
* console.log(minHeap.size); // 6;
*
* // Add new element
* minHeap.add(4);
* console.log(minHeap.size); // 7;
*
* // Min heap property: smallest element at root
* const min = minHeap.peek();
* console.log(min); // 1;
*/
add(element) {
this._elements.push(element);
return this._bubbleUp(this.elements.length - 1);
}
/**
* Insert many elements from an iterable.
* @remarks Time O(N log N), Space O(1)
* @param elements - Iterable of elements or raw values.
* @returns Array of per-element success flags.
* @example
* // Add multiple elements
* const heap = new Heap<number>([], { comparator: (a, b) => a - b });
* heap.addMany([5, 3, 7, 1]);
* console.log(heap.peek()); // 1;
* console.log(heap.size); // 4;
*/
addMany(elements) {
const flags = [];
for (const el of elements) {
if (this.toElementFn) {
const ok = this.add(this.toElementFn(el));
flags.push(ok);
} else {
const ok = this.add(el);
flags.push(ok);
}
}
return flags;
}
/**
* Remove and return the top element.
* @remarks Time O(log N), Space O(1)
* @returns Top element or undefined.
* @example
* // Heap with custom comparator (MaxHeap behavior)
* interface Task {
* id: number;
* priority: number;
* name: string;
* }
*
* // Custom comparator for max heap behavior (higher priority first)
* const tasks: Task[] = [
* { id: 1, priority: 5, name: 'Email' },
* { id: 2, priority: 3, name: 'Chat' },
* { id: 3, priority: 8, name: 'Alert' }
* ];
*
* const maxHeap = new Heap(tasks, {
* comparator: (a: Task, b: Task) => b.priority - a.priority
* });
*
* console.log(maxHeap.size); // 3;
*
* // Peek returns highest priority task
* const topTask = maxHeap.peek();
* console.log(topTask?.priority); // 8;
* console.log(topTask?.name); // 'Alert';
*/
/**
* @deprecated Use `pop` instead. Will be removed in a future major version.
* @example
* // Heap with custom comparator (MaxHeap behavior)
* interface Task {
* id: number;
* priority: number;
* name: string;
* }
*
* // Custom comparator for max heap behavior (higher priority first)
* const tasks: Task[] = [
* { id: 1, priority: 5, name: 'Email' },
* { id: 2, priority: 3, name: 'Chat' },
* { id: 3, priority: 8, name: 'Alert' }
* ];
*
* const maxHeap = new Heap(tasks, {
* comparator: (a: Task, b: Task) => b.priority - a.priority
* });
*
* console.log(maxHeap.size); // 3;
*
* // Peek returns highest priority task
* const topTask = maxHeap.peek();
* console.log(topTask?.priority); // 8;
* console.log(topTask?.name); // 'Alert';
*/
poll() {
return this.pop();
}
/**
* Remove and return the top element (min or max depending on comparator).
* @remarks Time O(log N) amortized, Space O(1)
* @returns The removed top element, or undefined if empty.
*/
pop() {
if (this.elements.length === 0) return;
const value = this.elements[0];
const last = this.elements.pop();
if (this.elements.length) {
this.elements[0] = last;
this._sinkDown(0, this.elements.length >> 1);
}
return value;
}
/**
* Get the current top element without removing it.
* @remarks Time O(1), Space O(1)
* @returns Top element or undefined.
* @example
* // Heap for event processing with priority
* interface Event {
* id: number;
* type: 'critical' | 'warning' | 'info';
* timestamp: number;
* message: string;
* }
*
* // Custom priority: critical > warning > info
* const priorityMap = { critical: 3, warning: 2, info: 1 };
*
* const eventHeap = new Heap<Event>([], {
* comparator: (a: Event, b: Event) => {
* const priorityA = priorityMap[a.type];
* const priorityB = priorityMap[b.type];
* return priorityB - priorityA; // Higher priority first
* }
* });
*
* // Add events in random order
* eventHeap.add({ id: 1, type: 'info', timestamp: 100, message: 'User logged in' });
* eventHeap.add({ id: 2, type: 'critical', timestamp: 101, message: 'Server down' });
* eventHeap.add({ id: 3, type: 'warning', timestamp: 102, message: 'High memory' });
* eventHeap.add({ id: 4, type: 'info', timestamp: 103, message: 'Cache cleared' });
* eventHeap.add({ id: 5, type: 'critical', timestamp: 104, message: 'Database error' });
*
* console.log(eventHeap.size); // 5;
*
* // Process events by priority (critical first)
* const processedOrder: Event[] = [];
* while (eventHeap.size > 0) {
* const event = eventHeap.poll();
* if (event) {
* processedOrder.push(event);
* }
* }
*
* // Verify critical events came first
* console.log(processedOrder[0].type); // 'critical';
* console.log(processedOrder[1].type); // 'critical';
* console.log(processedOrder[2].type); // 'warning';
* console.log(processedOrder[3].type); // 'info';
* console.log(processedOrder[4].type); // 'info';
*
* // Verify O(log n) operations
* const newHeap = new Heap<number>([5, 3, 7, 1]);
*
* // Add - O(log n)
* newHeap.add(2);
* console.log(newHeap.size); // 5;
*
* // Poll - O(log n)
* const removed = newHeap.poll();
* console.log(removed); // 1;
*
* // Peek - O(1)
* const top = newHeap.peek();
* console.log(top); // 2;
*/
peek() {
return this.elements[0];
}
/**
* Check whether the heap is empty.
* @remarks Time O(1), Space O(1)
* @returns True if size is 0.
* @example
* // Check if heap is empty
* const heap = new Heap<number>([], { comparator: (a, b) => a - b });
* console.log(heap.isEmpty()); // true;
* heap.add(1);
* console.log(heap.isEmpty()); // false;
*/
isEmpty() {
return this.size === 0;
}
/**
* Remove all elements.
* @remarks Time O(1), Space O(1)
* @returns void
* @example
* // Remove all elements
* const heap = new Heap<number>([1, 2, 3], { comparator: (a, b) => a - b });
* heap.clear();
* console.log(heap.isEmpty()); // true;
*/
clear() {
this._elements = [];
}
/**
* Check if an equal element exists in the heap.
* @remarks Time O(N), Space O(1)
* @param element - Element to search for.
* @returns True if found.
* @example
* // Check element existence
* const heap = new Heap<number>([3, 1, 2], { comparator: (a, b) => a - b });
* console.log(heap.has(1)); // true;
* console.log(heap.has(99)); // false;
*/
has(element) {
for (const el of this.elements) if (this._equals(el, element)) return true;
return false;
}
/**
* Delete one occurrence of an element.
* @remarks Time O(N), Space O(1)
* @param element - Element to delete.
* @returns True if an element was removed.
* @example
* // Remove specific element
* const heap = new Heap<number>([3, 1, 4, 1, 5], { comparator: (a, b) => a - b });
* heap.delete(4);
* console.log(heap.toArray().includes(4)); // false;
*/
delete(element) {
let index = -1;
for (let i = 0; i < this.elements.length; i++) {
if (this._equals(this.elements[i], element)) {
index = i;
break;
}
}
if (index < 0) return false;
if (index === 0) {
this.pop();
} else if (index === this.elements.length - 1) {
this.elements.pop();
} else {
this.elements.splice(index, 1, this.elements.pop());
this._bubbleUp(index);
this._sinkDown(index, this.elements.length >> 1);
}
return true;
}
/**
* @deprecated Use `deleteWhere` instead. Will be removed in a future major version.
*/
deleteBy(predicate) {
return this.deleteWhere(predicate);
}
/**
* Delete the first element that matches a predicate.
* @remarks Time O(N), Space O(1)
* @param predicate - Function (element, index, heap) → boolean.
* @returns True if an element was removed.
*/
deleteWhere(predicate) {
let idx = -1;
for (let i = 0; i < this.elements.length; i++) {
if (predicate(this.elements[i], i, this)) {
idx = i;
break;
}
}
if (idx < 0) return false;
if (idx === 0) {
this.pop();
} else if (idx === this.elements.length - 1) {
this.elements.pop();
} else {
this.elements.splice(idx, 1, this.elements.pop());
this._bubbleUp(idx);
this._sinkDown(idx, this.elements.length >> 1);
}
return true;
}
/**
* Set the equality comparator used by has/delete operations.
* @remarks Time O(1), Space O(1)
* @param equals - Equality predicate (a, b) → boolean.
* @returns This heap.
*/
setEquality(equals) {
this._equals = equals;
return this;
}
/**
* Traverse the binary heap as a complete binary tree and collect elements.
* @remarks Time O(N), Space O(H)
* @param [order] - Traversal order: 'PRE' | 'IN' | 'POST'.
* @returns Array of visited elements.
* @example
* // Depth-first traversal
* const heap = new Heap<number>([3, 1, 2], { comparator: (a, b) => a - b });
* const result = heap.dfs('IN');
* console.log(result.length); // 3;
*/
dfs(order = "PRE") {
const result = [];
const _dfs = /* @__PURE__ */ __name((index) => {
const left = 2 * index + 1, right = left + 1;
if (index < this.size) {
if (order === "IN") {
_dfs(left);
result.push(this.elements[index]);
_dfs(right);
} else if (order === "PRE") {
result.push(this.elements[index]);
_dfs(left);
_dfs(right);
} else if (order === "POST") {
_dfs(left);
_dfs(right);
result.push(this.elements[index]);
}
}
}, "_dfs");
_dfs(0);
return result;
}
/**
* Restore heap order bottom-up (heapify in-place).
* @remarks Time O(N), Space O(1)
* @returns Array of per-node results from fixing steps.
*/
fix() {
const results = [];
for (let i = Math.floor(this.size / 2) - 1; i >= 0; i--) {
results.push(this._sinkDown(i, this.elements.length >> 1));
}
return results;
}
/**
* Return all elements in ascending order by repeatedly polling.
* @remarks Time O(N log N), Space O(N)
* @returns Sorted array of elements.
* @example
* // Sort elements using heap
* const heap = new Heap<number>([5, 1, 3, 2, 4]);
* const sorted = heap.sort();
* console.log(sorted); // [1, 2, 3, 4, 5];
*/
sort() {
const visited = [];
const cloned = this._createInstance();
for (const x of this.elements) cloned.add(x);
while (!cloned.isEmpty()) {
const top = cloned.poll();
if (top !== void 0) visited.push(top);
}
return visited;
}
/**
* Deep clone this heap.
* @remarks Time O(N), Space O(N)
* @returns A new heap with the same elements.
* @example
* // Create independent copy
* const heap = new Heap<number>([3, 1, 4], { comparator: (a, b) => a - b });
* const copy = heap.clone();
* copy.poll();
* console.log(heap.size); // 3;
* console.log(copy.size); // 2;
*/
clone() {
const next = this._createInstance();
for (const x of this.elements) next.add(x);
return next;
}
/**
* Filter elements into a new heap of the same class.
* @remarks Time O(N log N), Space O(N)
* @param callback - Predicate (element, index, heap) → boolean to keep element.
* @param [thisArg] - Value for `this` inside the callback.
* @returns A new heap with the kept elements.
* @example
* // Filter elements
* const heap = new Heap<number>([1, 2, 3, 4, 5], { comparator: (a, b) => a - b });
* const evens = heap.filter(x => x % 2 === 0);
* console.log(evens.size); // 2;
*/
filter(callback, thisArg) {
const out = this._createInstance();
let i = 0;
for (const x of this) {
if (thisArg === void 0 ? callback(x, i++, this) : callback.call(thisArg, x, i++, this)) {
out.add(x);
} else {
i++;
}
}
return out;
}
/**
* Map elements into a new heap of possibly different element type.
* @remarks Time O(N log N), Space O(N)
* @template EM
* @template RM
* @param callback - Mapping function (element, index, heap) → newElement.
* @param options - Options for the output heap, including comparator for EM.
* @param [thisArg] - Value for `this` inside the callback.
* @returns A new heap with mapped elements.
* @example
* // Transform elements
* const heap = new Heap<number>([1, 2, 3], { comparator: (a, b) => a - b });
* const doubled = heap.map(x => x * 2, { comparator: (a, b) => a - b });
* console.log(doubled.peek()); // 2;
*/
map(callback, options, thisArg) {
const { comparator, toElementFn, ...rest } = options ?? {};
if (!comparator) raise(TypeError, ERR.comparatorRequired("Heap.map"));
const out = this._createLike([], { ...rest, comparator, toElementFn });
let i = 0;
for (const x of this) {
const v = thisArg === void 0 ? callback(x, i++, this) : callback.call(thisArg, x, i++, this);
out.add(v);
}
return out;
}
/**
* Map elements into a new heap of the same element type.
* @remarks Time O(N log N), Space O(N)
* @param callback - Mapping function (element, index, heap) → element.
* @param [thisArg] - Value for `this` inside the callback.
* @returns A new heap with mapped elements.
*/
mapSame(callback, thisArg) {
const out = this._createInstance();
let i = 0;
for (const x of this) {
const v = thisArg === void 0 ? callback(x, i++, this) : callback.call(thisArg, x, i++, this);
out.add(v);
}
return out;
}
_DEFAULT_COMPARATOR = /* @__PURE__ */ __name((a, b) => {
if (typeof a === "object" || typeof b === "object") {
raise(TypeError, ERR.comparatorRequired("Heap"));
}
if (a > b) return 1;
if (a < b) return -1;
return 0;
}, "_DEFAULT_COMPARATOR");
_comparator = this._DEFAULT_COMPARATOR;
/**
* Get the comparator used to order elements.
* @remarks Time O(1), Space O(1)
* @returns Comparator function.
*/
get comparator() {
return this._comparator;
}
*_getIterator() {
for (const element of this.elements) yield element;
}
_bubbleUp(index) {
const element = this.elements[index];
while (index > 0) {
const parent = index - 1 >> 1;
const parentItem = this.elements[parent];
if (this.comparator(parentItem, element) <= 0) break;
this.elements[index] = parentItem;
index = parent;
}
this.elements[index] = element;
return true;
}
_sinkDown(index, halfLength) {
const element = this.elements[index];
while (index < halfLength) {
let left = index << 1 | 1;
const right = left + 1;
let minItem = this.elements[left];
if (right < this.elements.length && this.comparator(minItem, this.elements[right]) > 0) {
left = right;
minItem = this.elements[right];
}
if (this.comparator(minItem, element) >= 0) break;
this.elements[index] = minItem;
index = left;
}
this.elements[index] = element;
return true;
}
/**
* (Protected) Create an empty instance of the same concrete class.
* @remarks Time O(1), Space O(1)
* @param [options] - Options to override comparator or toElementFn.
* @returns A like-kind empty heap instance.
*/
_createInstance(options) {
const Ctor = this.constructor;
return new Ctor([], { comparator: this.comparator, toElementFn: this.toElementFn, ...options ?? {} });
}
/**
* (Protected) Create a like-kind instance seeded by elements.
* @remarks Time O(N log N), Space O(N)
* @template EM
* @template RM
* @param [elements] - Iterable of elements or raw values to seed.
* @param [options] - Options forwarded to the constructor.
* @returns A like-kind heap instance.
*/
_createLike(elements = [], options) {
const Ctor = this.constructor;
return new Ctor(elements, options);
}
/**
* (Protected) Spawn an empty like-kind heap instance.
* @remarks Time O(1), Space O(1)
* @template EM
* @template RM
* @param [options] - Options forwarded to the constructor.
* @returns An empty like-kind heap instance.
*/
_spawnLike(options) {
return this._createLike([], options);
}
};
var FibonacciHeapNode = class {
static {
__name(this, "FibonacciHeapNode");
}
element;
degree;
left;
right;
child;
parent;
marked;
constructor(element, degree = 0) {
this.element = element;
this.degree = degree;
this.marked = false;
}
};
var FibonacciHeap = class {
static {
__name(this, "FibonacciHeap");
}
/**
* Create a FibonacciHeap.
* @remarks Time O(1), Space O(1)
* @param [comparator] - Comparator to order elements (min-heap by default).
* @returns New FibonacciHeap instance.
*/
constructor(comparator) {
this.clear();
this._comparator = comparator || this._defaultComparator;
if (typeof this.comparator !== "function") raise(TypeError, ERR.notAFunction("comparator", "FibonacciHeap"));
}
_root;
/**
* Get the circular root list head.
* @remarks Time O(1), Space O(1)
* @returns Root node or undefined.
*/
get root() {
return this._root;
}
_size = 0;
get size() {
return this._size;
}
_min;
/**
* Get the current minimum node.
* @remarks Time O(1), Space O(1)
* @returns Min node or undefined.
*/
get min() {
return this._min;
}
_comparator;
get comparator() {
return this._comparator;
}
clear() {
this._root = void 0;
this._min = void 0;
this._size = 0;
}
add(element) {
this.push(element);
return true;
}
/**
* Push an element into the root list.
* @remarks Time O(1) amortized, Space O(1)
* @param element - Element to insert.
* @returns True when the element is added.
*/
push(element) {
const node = this.createNode(element);
node.left = node;
node.right = node;
this.mergeWithRoot(node);
if (!this.min || this.comparator(node.element, this.min.element) <= 0) this._min = node;
this._size++;
return true;
}
peek() {
return this.min ? this.min.element : void 0;
}
/**
* Collect nodes from a circular doubly linked list starting at head.
* @remarks Time O(K), Space O(K)
* @param [head] - Start node of the circular list.
* @returns Array of nodes from the list.
*/
consumeLinkedList(head) {
const elements = [];
if (!head) return elements;
let node = head;
let started = false;
while (true) {
if (node === head && started) break;
else if (node === head) started = true;
elements.push(node);
node = node.right;
}
return elements;
}
/**
* Insert a node into a parent's child list (circular).
* @remarks Time O(1), Space O(1)
* @param parent - Parent node.
* @param node - Child node to insert.
* @returns void
*/
mergeWithChild(parent, node) {
if (!parent.child) parent.child = node;
else {
node.right = parent.child.right;
node.left = parent.child;
parent.child.right.left = node;
parent.child.right = node;
}
}
poll() {
return this.pop();
}
/**
* Remove and return the minimum element, consolidating the root list.
* @remarks Time O(log N) amortized, Space O(1)
* @returns Minimum element or undefined.
*/
pop() {
if (this._size === 0) return void 0;
const z = this.min;
if (z.child) {
const elements = this.consumeLinkedList(z.child);
for (const node of elements) {
this.mergeWithRoot(node);
node.parent = void 0;
}
}
this.removeFromRoot(z);
if (z === z.right) {
this._min = void 0;
this._root = void 0;
} else {
this._min = z.right;
this._consolidate();
}
this._size--;
return z.element;
}
/**
* Meld another heap into this heap.
* @remarks Time O(1), Space O(1)
* @param heapToMerge - Another FibonacciHeap to meld into this one.
* @returns void
*/
merge(heapToMerge) {
if (heapToMerge.size === 0) return;
if (this.root && heapToMerge.root) {
const thisRoot = this.root, otherRoot = heapToMerge.root;
const thisRootRight = thisRoot.right, otherRootLeft = otherRoot.left;
thisRoot.right = otherRoot;
otherRoot.left = thisRoot;
thisRootRight.left = otherRootLeft;
otherRootLeft.right = thisRootRight;
} else if (!this.root && heapToMerge.root) {
this._root = heapToMerge.root;
}
if (!this.min || heapToMerge.min && this.comparator(heapToMerge.min.element, this.min.element) < 0) {
this._min = heapToMerge.min;
}
this._size += heapToMerge.size;
heapToMerge.clear();
}
createNode(element) {
return new FibonacciHeapNode(element);
}
isEmpty() {
return this._size === 0;
}
_defaultComparator(a, b) {
if (a < b) return -1;
if (a > b) return 1;
return 0;
}
mergeWithRoot(node) {
if (!this.root) this._root = node;
else {
node.right = this.root.right;
node.left = this.root;
this.root.right.left = node;
this.root.right = node;
}
}
removeFromRoot(node) {
if (this.root === node) this._root = node.right;
if (node.left) node.left.right = node.right;
if (node.right) node.right.left = node.left;
}
_link(y, x) {
this.removeFromRoot(y);
y.left = y;
y.right = y;
this.mergeWithChild(x, y);
x.degree++;
y.parent = x;
}
_consolidate() {
const A = new Array(this._size);
const elements = this.consumeLinkedList(this.root);
let x, y, d, t;
for (const node of elements) {
x = node;
d = x.degree;
while (A[d]) {
y = A[d];
if (this.comparator(x.element, y.element) > 0) {
t = x;
x = y;
y = t;
}
this._link(y, x);
A[d] = void 0;
d++;
}
A[d] = x;
}
for (let i = 0; i < A.length; i++) {
if (A[i] && (!this.min || this.comparator(A[i].element, this.min.element) <= 0)) this._min = A[i];
}
}
};
// src/data-structures/priority-queue/priority-queue.ts
var PriorityQueue = class extends Heap {
static {
__name(this, "PriorityQueue");
}
constructor(elements = [], options) {
super(elements, options);
}
};
// src/data-structures/priority-queue/min-priority-queue.ts
var MinPriorityQueue = class extends PriorityQueue {
static {
__name(this, "MinPriorityQueue");
}
/**
* Creates a min-priority queue.
* @param elements Optional initial elements to insert.
* @param options Optional configuration (e.g., `comparator`, `toElementFn`).
* @remarks Complexity — Time: O(n log n) when inserting n elements incrementally; Space: O(n).
*/
constructor(elements = [], options) {
super(elements, options);
}
};
/**
* data-structure-typed
*
* @author Pablo Zeng
* @copyright Copyright (c) 2022 Pablo Zeng <zrwusa@gmail.com>
* @license MIT License
*/
/**
* data-structure-typed
*
* @author Kirk Qi
* @copyright Copyright (c) 2022 Kirk Qi <qilinaus@gmail.com>
* @license MIT License
*/
export { DFSOperation, ERR, FibonacciHeap, FibonacciHeapNode, Heap, MinPriorityQueue, PriorityQueue, Range, raise };
//# sourceMappingURL=index.mjs.map
//# sourceMappingURL=index.mjs.map