export class PairingHeap { private subheaps : PairingHeap[]; // from: https://gist.github.com/nervoussystem //{elem:object, subheaps:[array of heaps]} constructor(public elem: T) { this.subheaps = []; } public toString(selector) : string { var str = "", needComma = false; for (var i = 0; i < this.subheaps.length; ++i) { var subheap: PairingHeap = this.subheaps[i]; if (!subheap.elem) { needComma = false; continue; } if (needComma) { str = str + ","; } str = str + subheap.toString(selector); needComma = true; } if (str !== "") { str = "(" + str + ")"; } return (this.elem ? selector(this.elem) : "") + str; } public forEach(f) { if (!this.empty()) { f(this.elem, this); this.subheaps.forEach(s => s.forEach(f)); } } public count(): number { return this.empty() ? 0 : 1 + this.subheaps.reduce((n: number, h: PairingHeap) => { return n + h.count(); }, 0); } public min() : T { return this.elem; } public empty() : boolean { return this.elem == null; } public contains(h: PairingHeap): boolean { if (this === h) return true; for (var i = 0; i < this.subheaps.length; i++) { if (this.subheaps[i].contains(h)) return true; } return false; } public isHeap(lessThan: (a: T, b: T) => boolean): boolean { return this.subheaps.every(h=> lessThan(this.elem, h.elem) && h.isHeap(lessThan)); } public insert(obj : T, lessThan) : PairingHeap { return this.merge(new PairingHeap(obj), lessThan); } public merge(heap2: PairingHeap, lessThan): PairingHeap { if (this.empty()) return heap2; else if (heap2.empty()) return this; else if (lessThan(this.elem, heap2.elem)) { this.subheaps.push(heap2); return this; } else { heap2.subheaps.push(this); return heap2; } } public removeMin(lessThan: (a: T, b: T) => boolean): PairingHeap { if (this.empty()) return null; else return this.mergePairs(lessThan); } public mergePairs(lessThan: (a: T, b: T) => boolean) : PairingHeap { if (this.subheaps.length == 0) return new PairingHeap(null); else if (this.subheaps.length == 1) { return this.subheaps[0]; } else { var firstPair = this.subheaps.pop().merge(this.subheaps.pop(), lessThan); var remaining = this.mergePairs(lessThan); return firstPair.merge(remaining, lessThan); } } public decreaseKey(subheap: PairingHeap, newValue: T, setHeapNode: (e: T, h: PairingHeap)=>void, lessThan: (a: T, b: T) => boolean): PairingHeap { var newHeap = subheap.removeMin(lessThan); //reassign subheap values to preserve tree subheap.elem = newHeap.elem; subheap.subheaps = newHeap.subheaps; if (setHeapNode !== null && newHeap.elem !== null) { setHeapNode(subheap.elem, subheap); } var pairingNode = new PairingHeap(newValue); if (setHeapNode !== null) { setHeapNode(newValue, pairingNode); } return this.merge(pairingNode, lessThan); } } /** * @class PriorityQueue a min priority queue backed by a pairing heap */ export class PriorityQueue { private root : PairingHeap; constructor(private lessThan: (a: T, b: T) => boolean) { } /** * @method top * @return the top element (the min element as defined by lessThan) */ public top() : T { if (this.empty()) { return null; } return this.root.elem; } /** * @method push * put things on the heap */ public push(...args: T[]): PairingHeap { var pairingNode; for (var i = 0, arg; arg=args[i]; ++i) { pairingNode = new PairingHeap(arg); this.root = this.empty() ? pairingNode : this.root.merge(pairingNode, this.lessThan); } return pairingNode; } /** * @method empty * @return true if no more elements in queue */ public empty(): boolean { return !this.root || !this.root.elem; } /** * @method isHeap check heap condition (for testing) * @return true if queue is in valid state */ public isHeap(): boolean { return this.root.isHeap(this.lessThan); } /** * @method forEach apply f to each element of the queue * @param f function to apply */ public forEach(f) { this.root.forEach(f); } /** * @method pop remove and return the min element from the queue */ public pop(): T { if (this.empty()) { return null; } var obj = this.root.min(); this.root = this.root.removeMin(this.lessThan); return obj; } /** * @method reduceKey reduce the key value of the specified heap node */ public reduceKey(heapNode: PairingHeap, newKey: T, setHeapNode: (e: T, h: PairingHeap)=>void = null): void { this.root = this.root.decreaseKey(heapNode, newKey, setHeapNode, this.lessThan); } public toString(selector) { return this.root.toString(selector); } /** * @method count * @return number of elements in queue */ public count() { return this.root.count(); } }