import { isIterable, isArrayLike } from '../core/traits'; import { slice } from '../core/array'; import { makeHeap, pushHeap, popHeap, replaceHeap } from '../algorithms/binaryHeap'; import { compare } from '../functional/compare'; export class PriorityQueue { protected _data: T[]; protected _size: number; protected _compare: (lhs: T, rhs: T) => number; constructor(capacity: number, comparefn?: (lhs: T, rhs: T) => number); constructor(data: ArrayLike | Iterable, comparefn?: (lhs: T, rhs: T) => number); constructor(comparefn?: (lhs: T, rhs: T) => number); constructor(arg1?: any, arg2?: any) { if (typeof arg1 === 'number') { this._data = new Array(arg1); this._size = 0; arg1 = arg2; } else if (isIterable(arg1)) { this._data = [...arg1]; this._size = this._data.length; arg1 = arg2; } else if (isArrayLike(arg1)) { this._data = slice(arg1); this._size = this._data.length; arg1 = arg2; } else { this._data = []; this._size = 0; } this._compare = typeof arg1 === 'function' ? arg1 : compare; makeHeap(this._data, this._compare, 0, this._size); } get capacity() { return this._data.length; } get size() { return this._size; } shrinkToFit() { this._data.length = this._size; } isEmpty() { return this._size === 0; } top() { return this._data[0]; } push(...values: T[]) { for (const value of values) { if (this._size < this._data.length) this._data[this._size] = value; else this._data.push(value); this._size++; pushHeap(this._data, this._compare, 0, this._size); } } pop() { popHeap(this._data, this._compare, 0, this._size); if (this._size > 0) return this._data[--this._size]; } replace(index: number, value: T) { replaceHeap(this._data, index, value, this._compare, 0, this._size); } slice(start?: number, end?: number) { return this._data.slice(start, end); } *[Symbol.iterator]() { const length = this._data.length; for (let i = 0; i < length; i++) yield this._data[i]; } }