UNPKG

libstl

Version:

Standard JavaScript/TypeScript Library: DoublyLinkedList, Stack, Queue, Heap, MaxHeap, MinHeap, PriorityQueue

355 lines (317 loc) 8.14 kB
/** * The Heap class provides the main functionality of a Heap. * * @class Heap */ class Heap { /** * Max heap flag * * @property MAX * @type number * @static */ public static MAX:number = 1; /** * Min heap flag * * @property MIN * @type number * @static */ public static MIN:number = -1; /** * Binary tree storage array * * @property _tree * @type Array * @private */ private _tree:Array<any> = []; /** * Heap type * * @property _type * @type number * @private */ protected _type:number = Heap.MAX; /** * Iteration pointer * * @property _key * @type number * @private */ private _key = 0; /** * Get index of left child element in binary tree stored in array * * @method _child * @param n * @return number * @private */ private _child(n:number):number { return 2 * n + 1; } /** * Get index of parent element in binary tree stored in array * * @method _parent * @param n * @return number * @private */ private _parent(n:number):number { //console.log('n=', n, Math.floor(n / 2)); return Math.floor(n / 2); } /** * Swap 2 elements in binary tree * * @method _swap * @param first * @param second * @private */ private _swap(first:number, second:number):void { var swap = this._tree[first]; this._tree[first] = this._tree[second]; this._tree[second] = swap; } /** * Sift elements in binary tree * * @method _siftUp * @param i * @private */ private _siftUp(i:number):void { while (i > 0) { var parent = this._parent(i); if (this.compare(this._tree[i], this._tree[parent]) * this._type > 0) { this._swap(i, parent); i = parent; } else { break; } } } /** * Sift down elements in binary tree * * @method _siftDown * @param i * @private */ private _siftDown(i:number):void { while (i < this._tree.length) { var left = this._child(i); var right = left + 1; if ((left < this._tree.length) && (right < this._tree.length) && (this.compare(this._tree[i], this._tree[left]) * this._type < 0 || this.compare(this._tree[i], this._tree[right]) * this._type < 0)) { // there is 2 children and one of them must be swapped // get correct element to sift down var sift = left; if (this.compare(this._tree[left], this._tree[right]) * this._type < 0) { sift = right; } this._swap(i, sift); i = sift; } else if (left < this._tree.length && this.compare(this._tree[i], this._tree[left]) * this._type < 0) { // only one child exists this._swap(i, left); i = left; } else { break; } } } /** * Extracts a node from top of the heap and sift up * * @method extract * @return any The value of the extracted node. */ public extract():any { if (this._tree.length === 0) { throw new Error("Can't extract from an empty data structure"); } var extracted:any = this._tree[0]; if (this._tree.length === 1) { this._tree = []; } else { this._tree[0] = this._tree.pop(); this._siftDown(0); } return extracted; } /** * Inserts an element in the heap by sifting it up * * @method insert * @param value The value to insert. * @return void */ public insert(value:any):void { this._tree.push(value); this._siftUp(this._tree.length - 1); } /** * Peeks at the node from the top of the heap * * @method top * @return any The value of the node on the top. */ public top():any { if (this._tree.length === 0) { throw new Error("Can't peek at an empty heap"); } return this._tree[0]; } /** * Counts the number of elements in the heap * * @method count * @return number the number of elements in the heap. */ public count():number { return this._tree.length; } /** * Checks whether the heap is empty * * @method isEmpty * @return boolean whether the heap is empty. */ public isEmpty():boolean { return (this._tree.length === 0); } /** * Rewind iterator back to the start (no-op) * * @method rewind * @return void */ public rewind():void { this._key = 0; } /** * Return current node pointed by the iterator * * @method current * @return any The current node value. */ public current():any { return this._tree[this._key]; } /** * Return current node index * * @method key * @return any The current node index. */ public key():any { return this._key; } /** * Move to the next node * * @method next * @return void */ public next():void { this._key++; } /** * Move to previous entry * * @method prev * @return void */ public prev():void { this._key--; } /** * Check whether the heap contains more nodes * * @method valid * @return boolean true if the heap contains any more nodes, false otherwise. */ public valid():boolean { return (this._key >= 0 && this._key < this._tree.length); } /** * Compare elements in order to place them correctly in the heap while sifting up. * * @method compare * @param first The value of the first node being compared. * @param second The value of the second node being compared. * @return number Result of the comparison, positive integer if first is greater than second, 0 if they are equal, negative integer otherwise. * Having multiple elements with the same value in a Heap is not recommended. They will end up in an arbitrary relative position. */ public compare(first:any, second:any):number { if (first > second) { return 1; } else if (first == second) { return 0; } else { return -1; } } /** * Visually display heap tree * * @method _displayNode * @param node * @param prefix * @param last * @return String * @private */ private _displayNode(node, prefix = '', last = true) { var line = prefix; // get child indexes var left = this._child(node); var right = left + 1; if (last) { line += (prefix ? '└─' : ' '); } else { line += '├─'; } line += this._tree[node]; prefix += (last ? ' ' : '│ '); if (left < this._tree.length) { line += '\n' + this._displayNode(left, prefix, (this._tree[right] == undefined ? true : false)); } if (right < this._tree.length) { line += '\n' + this._displayNode(right, prefix, true); } return line; } /** * Serializes the heap to string * * @method toString * @return string The serialized string. */ public toString():string { // start with root and recursively goes to each node return this._displayNode(0); } /** * Serializes the heap to array * * @method toArray * @return Array The serialized array. */ public toArray():Array<any> { return this._tree; } } export = Heap;