API Docs for: 0.1.21
Show:

File: Datastructures/Heap.ts

/**
 * 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 {
        return Math.floor(n - 1 / 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;