webcola
Version:
WebCola =======
185 lines (171 loc) • 5.85 kB
text/typescript
export class PairingHeap<T> {
private subheaps : PairingHeap<T>[];
// 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<T> = 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<T>) => {
return n + h.count();
}, 0);
}
public min() : T {
return this.elem;
}
public empty() : boolean {
return this.elem == null;
}
public contains(h: PairingHeap<T>): 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<T> {
return this.merge(new PairingHeap<T>(obj), lessThan);
}
public merge(heap2: PairingHeap<T>, lessThan): PairingHeap<T> {
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<T> {
if (this.empty()) return null;
else return this.mergePairs(lessThan);
}
public mergePairs(lessThan: (a: T, b: T) => boolean) : PairingHeap<T> {
if (this.subheaps.length == 0) return new PairingHeap<T>(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<T>, newValue: T, setHeapNode: (e: T, h: PairingHeap<T>)=>void, lessThan: (a: T, b: T) => boolean): PairingHeap<T> {
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<T> {
private root : PairingHeap<T>;
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<T> {
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<T>, newKey: T, setHeapNode: (e: T, h: PairingHeap<T>)=>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();
}
}