UNPKG

typescript-collections

Version:

A complete, fully tested data structure library written in TypeScript.

1,381 lines (1,375 loc) 296 kB
(function(f) { if (typeof exports === "object" && typeof module !== "undefined") { module.exports = f() } else if (typeof define === "function" && define.amd) { define([], f) } else { var g; if (typeof window !== "undefined") { g = window } else if (typeof global !== "undefined") { g = global } else if (typeof self !== "undefined") { g = self } else { g = this } g.listComponent = f() } })(function() { var define, module, exports; require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ "use strict"; var __extends = (this && this.__extends) || (function () { var extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); Object.defineProperty(exports, "__esModule", { value: true }); var BSTreeKV_1 = require("./BSTreeKV"); /** * Special-case of the binary search tree in which the search key is equal to the element type. * This definition is suitable when the element type can not be split between what defines its order * and what does not (eg. primitive types as opposed to indexed records). * * The table below shows some use-case examples for both interfaces: * * element type | most suitable interface * ------------------------------------|---------------------------- * number | BSTree<number> * string | BSTree<string> * { order: number, data: string } | BSTreeKV<{order: number}, {order: number, data: string}> * * @see BSTreeKV */ var BSTree = /** @class */ (function (_super) { __extends(BSTree, _super); function BSTree() { return _super !== null && _super.apply(this, arguments) || this; } return BSTree; }(BSTreeKV_1.default)); exports.default = BSTree; },{"./BSTreeKV":2}],2:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var util = require("./util"); var Queue_1 = require("./Queue"); /** * General binary search tree implementation. * * This interface allows one to search elements using a subset of their attributes (thus the * tree can be used as an index for complex objects). * The attributes required to define an ordering in the tree must be defined in the type K. * Any additional attribute must be defined in the type V. * * @see BSTree */ var BSTreeKV = /** @class */ (function () { /** * Creates an empty binary search tree. * @class <p>A binary search tree is a binary tree in which each * internal node stores an element such that the elements stored in the * left subtree are less than it and the elements * stored in the right subtree are greater.</p> * <p>Formally, a binary search tree is a node-based binary tree data structure which * has the following properties:</p> * <ul> * <li>The left subtree of a node contains only nodes with elements less * than the node's element</li> * <li>The right subtree of a node contains only nodes with elements greater * than the node's element</li> * <li>Both the left and right subtrees must also be binary search trees.</li> * </ul> * <p>If the inserted elements are custom objects a compare function must * be provided at construction time, otherwise the <=, === and >= operators are * used to compare elements. Example:</p> * <pre> * function compare(a, b) { * if (a is less than b by some ordering criterion) { * return -1; * } if (a is greater than b by the ordering criterion) { * return 1; * } * // a must be equal to b * return 0; * } * </pre> * @constructor * @param {function(Object,Object):number=} compareFunction optional * function used to compare two elements. Must return a negative integer, * zero, or a positive integer as the first argument is less than, equal to, * or greater than the second. */ function BSTreeKV(compareFunction) { this.root = null; this.compare = compareFunction || util.defaultCompare; this.nElements = 0; } /** * Adds the specified element to this tree if it is not already present. * @param {Object} element the element to insert. * @return {boolean} true if this tree did not already contain the specified element. */ BSTreeKV.prototype.add = function (element) { if (util.isUndefined(element)) { return false; } if (this.insertNode(this.createNode(element)) !== null) { this.nElements++; return true; } return false; }; /** * Removes all of the elements from this tree. */ BSTreeKV.prototype.clear = function () { this.root = null; this.nElements = 0; }; /** * Returns true if this tree contains no elements. * @return {boolean} true if this tree contains no elements. */ BSTreeKV.prototype.isEmpty = function () { return this.nElements === 0; }; /** * Returns the number of elements in this tree. * @return {number} the number of elements in this tree. */ BSTreeKV.prototype.size = function () { return this.nElements; }; /** * Returns true if this tree contains the specified element. * @param {Object} element element to search for. * @return {boolean} true if this tree contains the specified element, * false otherwise. */ BSTreeKV.prototype.contains = function (element) { if (util.isUndefined(element)) { return false; } return this.searchNode(this.root, element) !== null; }; /** * Looks for the value with the provided search key. * @param {Object} element The key to look for * @return {Object} The value found or undefined if it was not found. */ BSTreeKV.prototype.search = function (element) { var ret = this.searchNode(this.root, element); if (ret === null) { return undefined; } return ret.element; }; /** * Removes the specified element from this tree if it is present. * @return {boolean} true if this tree contained the specified element. */ BSTreeKV.prototype.remove = function (element) { var node = this.searchNode(this.root, element); if (node === null) { return false; } this.removeNode(node); this.nElements--; return true; }; /** * Executes the provided function once for each element present in this tree in * in-order. * @param {function(Object):*} callback function to execute, it is invoked with one * argument: the element value, to break the iteration you can optionally return false. */ BSTreeKV.prototype.inorderTraversal = function (callback) { this.inorderTraversalAux(this.root, callback, { stop: false }); }; /** * Executes the provided function once for each element present in this tree in pre-order. * @param {function(Object):*} callback function to execute, it is invoked with one * argument: the element value, to break the iteration you can optionally return false. */ BSTreeKV.prototype.preorderTraversal = function (callback) { this.preorderTraversalAux(this.root, callback, { stop: false }); }; /** * Executes the provided function once for each element present in this tree in post-order. * @param {function(Object):*} callback function to execute, it is invoked with one * argument: the element value, to break the iteration you can optionally return false. */ BSTreeKV.prototype.postorderTraversal = function (callback) { this.postorderTraversalAux(this.root, callback, { stop: false }); }; /** * Executes the provided function once for each element present in this tree in * level-order. * @param {function(Object):*} callback function to execute, it is invoked with one * argument: the element value, to break the iteration you can optionally return false. */ BSTreeKV.prototype.levelTraversal = function (callback) { this.levelTraversalAux(this.root, callback); }; /** * Returns the minimum element of this tree. * @return {*} the minimum element of this tree or undefined if this tree is * is empty. */ BSTreeKV.prototype.minimum = function () { if (this.isEmpty() || this.root === null) { return undefined; } return this.minimumAux(this.root).element; }; /** * Returns the maximum element of this tree. * @return {*} the maximum element of this tree or undefined if this tree is * is empty. */ BSTreeKV.prototype.maximum = function () { if (this.isEmpty() || this.root === null) { return undefined; } return this.maximumAux(this.root).element; }; /** * Executes the provided function once for each element present in this tree in inorder. * Equivalent to inorderTraversal. * @param {function(Object):*} callback function to execute, it is * invoked with one argument: the element value, to break the iteration you can * optionally return false. */ BSTreeKV.prototype.forEach = function (callback) { this.inorderTraversal(callback); }; /** * Returns an array containing all of the elements in this tree in in-order. * @return {Array} an array containing all of the elements in this tree in in-order. */ BSTreeKV.prototype.toArray = function () { var array = []; this.inorderTraversal(function (element) { array.push(element); return true; }); return array; }; /** * Returns the height of this tree. * @return {number} the height of this tree or -1 if is empty. */ BSTreeKV.prototype.height = function () { return this.heightAux(this.root); }; /** * @private */ BSTreeKV.prototype.searchNode = function (node, element) { var cmp = 1; while (node !== null && cmp !== 0) { cmp = this.compare(element, node.element); if (cmp < 0) { node = node.leftCh; } else if (cmp > 0) { node = node.rightCh; } } return node; }; /** * @private */ BSTreeKV.prototype.transplant = function (n1, n2) { if (n1.parent === null) { this.root = n2; } else if (n1 === n1.parent.leftCh) { n1.parent.leftCh = n2; } else { n1.parent.rightCh = n2; } if (n2 !== null) { n2.parent = n1.parent; } }; /** * @private */ BSTreeKV.prototype.removeNode = function (node) { if (node.leftCh === null) { this.transplant(node, node.rightCh); } else if (node.rightCh === null) { this.transplant(node, node.leftCh); } else { var y = this.minimumAux(node.rightCh); if (y.parent !== node) { this.transplant(y, y.rightCh); y.rightCh = node.rightCh; y.rightCh.parent = y; } this.transplant(node, y); y.leftCh = node.leftCh; y.leftCh.parent = y; } }; /** * @private */ BSTreeKV.prototype.inorderTraversalAux = function (node, callback, signal) { if (node === null || signal.stop) { return; } this.inorderTraversalAux(node.leftCh, callback, signal); if (signal.stop) { return; } signal.stop = callback(node.element) === false; if (signal.stop) { return; } this.inorderTraversalAux(node.rightCh, callback, signal); }; /** * @private */ BSTreeKV.prototype.levelTraversalAux = function (node, callback) { var queue = new Queue_1.default(); if (node !== null) { queue.enqueue(node); } node = queue.dequeue() || null; while (node != null) { if (callback(node.element) === false) { return; } if (node.leftCh !== null) { queue.enqueue(node.leftCh); } if (node.rightCh !== null) { queue.enqueue(node.rightCh); } node = queue.dequeue() || null; } }; /** * @private */ BSTreeKV.prototype.preorderTraversalAux = function (node, callback, signal) { if (node === null || signal.stop) { return; } signal.stop = callback(node.element) === false; if (signal.stop) { return; } this.preorderTraversalAux(node.leftCh, callback, signal); if (signal.stop) { return; } this.preorderTraversalAux(node.rightCh, callback, signal); }; /** * @private */ BSTreeKV.prototype.postorderTraversalAux = function (node, callback, signal) { if (node === null || signal.stop) { return; } this.postorderTraversalAux(node.leftCh, callback, signal); if (signal.stop) { return; } this.postorderTraversalAux(node.rightCh, callback, signal); if (signal.stop) { return; } signal.stop = callback(node.element) === false; }; BSTreeKV.prototype.minimumAux = function (node) { while (node != null && node.leftCh !== null) { node = node.leftCh; } return node; }; BSTreeKV.prototype.maximumAux = function (node) { while (node != null && node.rightCh !== null) { node = node.rightCh; } return node; }; /** * @private */ BSTreeKV.prototype.heightAux = function (node) { if (node === null) { return -1; } return Math.max(this.heightAux(node.leftCh), this.heightAux(node.rightCh)) + 1; }; /* * @private */ BSTreeKV.prototype.insertNode = function (node) { var parent = null; var position = this.root; while (position !== null) { var cmp = this.compare(node.element, position.element); if (cmp === 0) { return null; } else if (cmp < 0) { parent = position; position = position.leftCh; } else { parent = position; position = position.rightCh; } } node.parent = parent; if (parent === null) { // tree is empty this.root = node; } else if (this.compare(node.element, parent.element) < 0) { parent.leftCh = node; } else { parent.rightCh = node; } return node; }; /** * @private */ BSTreeKV.prototype.createNode = function (element) { return { element: element, leftCh: null, rightCh: null, parent: null }; }; return BSTreeKV; }()); exports.default = BSTreeKV; },{"./Queue":12,"./util":16}],3:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var util = require("./util"); var Dictionary_1 = require("./Dictionary"); var Set_1 = require("./Set"); var Bag = /** @class */ (function () { /** * Creates an empty bag. * @class <p>A bag is a special kind of set in which members are * allowed to appear more than once.</p> * <p>If the inserted elements are custom objects a function * which converts elements to unique strings must be provided. Example:</p> * * <pre> * function petToString(pet) { * return pet.name; * } * </pre> * * @constructor * @param {function(Object):string=} toStrFunction optional function used * to convert elements to strings. If the elements aren't strings or if toString() * is not appropriate, a custom function which receives an object and returns a * unique string must be provided. */ function Bag(toStrFunction) { this.toStrF = toStrFunction || util.defaultToString; this.dictionary = new Dictionary_1.default(this.toStrF); this.nElements = 0; } /** * Adds nCopies of the specified object to this bag. * @param {Object} element element to add. * @param {number=} nCopies the number of copies to add, if this argument is * undefined 1 copy is added. * @return {boolean} true unless element is undefined. */ Bag.prototype.add = function (element, nCopies) { if (nCopies === void 0) { nCopies = 1; } if (util.isUndefined(element) || nCopies <= 0) { return false; } if (!this.contains(element)) { var node = { value: element, copies: nCopies }; this.dictionary.setValue(element, node); } else { this.dictionary.getValue(element).copies += nCopies; } this.nElements += nCopies; return true; }; /** * Counts the number of copies of the specified object in this bag. * @param {Object} element the object to search for.. * @return {number} the number of copies of the object, 0 if not found */ Bag.prototype.count = function (element) { if (!this.contains(element)) { return 0; } else { return this.dictionary.getValue(element).copies; } }; /** * Returns true if this bag contains the specified element. * @param {Object} element element to search for. * @return {boolean} true if this bag contains the specified element, * false otherwise. */ Bag.prototype.contains = function (element) { return this.dictionary.containsKey(element); }; /** * Removes nCopies of the specified object to this bag. * If the number of copies to remove is greater than the actual number * of copies in the Bag, all copies are removed. * @param {Object} element element to remove. * @param {number=} nCopies the number of copies to remove, if this argument is * undefined 1 copy is removed. * @return {boolean} true if at least 1 element was removed. */ Bag.prototype.remove = function (element, nCopies) { if (nCopies === void 0) { nCopies = 1; } if (util.isUndefined(element) || nCopies <= 0) { return false; } if (!this.contains(element)) { return false; } else { var node = this.dictionary.getValue(element); if (nCopies > node.copies) { this.nElements -= node.copies; } else { this.nElements -= nCopies; } node.copies -= nCopies; if (node.copies <= 0) { this.dictionary.remove(element); } return true; } }; /** * Returns an array containing all of the elements in this big in arbitrary order, * including multiple copies. * @return {Array} an array containing all of the elements in this bag. */ Bag.prototype.toArray = function () { var a = []; var values = this.dictionary.values(); for (var _i = 0, values_1 = values; _i < values_1.length; _i++) { var node = values_1[_i]; var element = node.value; var copies = node.copies; for (var j = 0; j < copies; j++) { a.push(element); } } return a; }; /** * Returns a set of unique elements in this bag. * @return {collections.Set<T>} a set of unique elements in this bag. */ Bag.prototype.toSet = function () { var toret = new Set_1.default(this.toStrF); var elements = this.dictionary.values(); for (var _i = 0, elements_1 = elements; _i < elements_1.length; _i++) { var ele = elements_1[_i]; var value = ele.value; toret.add(value); } return toret; }; /** * Executes the provided function once for each element * present in this bag, including multiple copies. * @param {function(Object):*} callback function to execute, it is * invoked with one argument: the element. To break the iteration you can * optionally return false. */ Bag.prototype.forEach = function (callback) { this.dictionary.forEach(function (k, v) { var value = v.value; var copies = v.copies; for (var i = 0; i < copies; i++) { if (callback(value) === false) { return false; } } return true; }); }; /** * Returns the number of elements in this bag. * @return {number} the number of elements in this bag. */ Bag.prototype.size = function () { return this.nElements; }; /** * Returns true if this bag contains no elements. * @return {boolean} true if this bag contains no elements. */ Bag.prototype.isEmpty = function () { return this.nElements === 0; }; /** * Removes all of the elements from this bag. */ Bag.prototype.clear = function () { this.nElements = 0; this.dictionary.clear(); }; return Bag; }()); // End of bag exports.default = Bag; },{"./Dictionary":4,"./Set":13,"./util":16}],4:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var util = require("./util"); var Dictionary = /** @class */ (function () { /** * Creates an empty dictionary. * @class <p>Dictionaries map keys to values; each key can map to at most one value. * This implementation accepts any kind of objects as keys.</p> * * <p>If the keys are custom objects a function which converts keys to unique * strings must be provided. Example:</p> * <pre> * function petToString(pet) { * return pet.name; * } * </pre> * @constructor * @param {function(Object):string=} toStrFunction optional function used * to convert keys to strings. If the keys aren't strings or if toString() * is not appropriate, a custom function which receives a key and returns a * unique string must be provided. */ function Dictionary(toStrFunction) { this.table = {}; this.nElements = 0; this.toStr = toStrFunction || util.defaultToString; } /** * Returns the value to which this dictionary maps the specified key. * Returns undefined if this dictionary contains no mapping for this key. * @param {Object} key key whose associated value is to be returned. * @return {*} the value to which this dictionary maps the specified key or * undefined if the map contains no mapping for this key. */ Dictionary.prototype.getValue = function (key) { var pair = this.table['$' + this.toStr(key)]; if (util.isUndefined(pair)) { return undefined; } return pair.value; }; /** * Associates the specified value with the specified key in this dictionary. * If the dictionary previously contained a mapping for this key, the old * value is replaced by the specified value. * @param {Object} key key with which the specified value is to be * associated. * @param {Object} value value to be associated with the specified key. * @return {*} previous value associated with the specified key, or undefined if * there was no mapping for the key or if the key/value are undefined. */ Dictionary.prototype.setValue = function (key, value) { if (util.isUndefined(key) || util.isUndefined(value)) { return undefined; } var ret; var k = '$' + this.toStr(key); var previousElement = this.table[k]; if (util.isUndefined(previousElement)) { this.nElements++; ret = undefined; } else { ret = previousElement.value; } this.table[k] = { key: key, value: value }; return ret; }; /** * Removes the mapping for this key from this dictionary if it is present. * @param {Object} key key whose mapping is to be removed from the * dictionary. * @return {*} previous value associated with specified key, or undefined if * there was no mapping for key. */ Dictionary.prototype.remove = function (key) { var k = '$' + this.toStr(key); var previousElement = this.table[k]; if (!util.isUndefined(previousElement)) { delete this.table[k]; this.nElements--; return previousElement.value; } return undefined; }; /** * Returns an array containing all of the keys in this dictionary. * @return {Array} an array containing all of the keys in this dictionary. */ Dictionary.prototype.keys = function () { var array = []; for (var name_1 in this.table) { if (util.has(this.table, name_1)) { var pair = this.table[name_1]; array.push(pair.key); } } return array; }; /** * Returns an array containing all of the values in this dictionary. * @return {Array} an array containing all of the values in this dictionary. */ Dictionary.prototype.values = function () { var array = []; for (var name_2 in this.table) { if (util.has(this.table, name_2)) { var pair = this.table[name_2]; array.push(pair.value); } } return array; }; /** * Executes the provided function once for each key-value pair * present in this dictionary. * @param {function(Object,Object):*} callback function to execute, it is * invoked with two arguments: key and value. To break the iteration you can * optionally return false. */ Dictionary.prototype.forEach = function (callback) { for (var name_3 in this.table) { if (util.has(this.table, name_3)) { var pair = this.table[name_3]; var ret = callback(pair.key, pair.value); if (ret === false) { return; } } } }; /** * Returns true if this dictionary contains a mapping for the specified key. * @param {Object} key key whose presence in this dictionary is to be * tested. * @return {boolean} true if this dictionary contains a mapping for the * specified key. */ Dictionary.prototype.containsKey = function (key) { return !util.isUndefined(this.getValue(key)); }; /** * Removes all mappings from this dictionary. * @this {collections.Dictionary} */ Dictionary.prototype.clear = function () { this.table = {}; this.nElements = 0; }; /** * Returns the number of keys in this dictionary. * @return {number} the number of key-value mappings in this dictionary. */ Dictionary.prototype.size = function () { return this.nElements; }; /** * Returns true if this dictionary contains no mappings. * @return {boolean} true if this dictionary contains no mappings. */ Dictionary.prototype.isEmpty = function () { return this.nElements <= 0; }; Dictionary.prototype.toString = function () { var toret = '{'; this.forEach(function (k, v) { toret += "\n\t" + k + " : " + v; }); return toret + '\n}'; }; return Dictionary; }()); // End of dictionary exports.default = Dictionary; },{"./util":16}],5:[function(require,module,exports){ "use strict"; var __extends = (this && this.__extends) || (function () { var extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); Object.defineProperty(exports, "__esModule", { value: true }); var Dictionary_1 = require("./Dictionary"); var util = require("./util"); var FactoryDictionary = /** @class */ (function (_super) { __extends(FactoryDictionary, _super); /** * Creates an empty dictionary. * @class <p>Dictionaries map keys to values; each key can map to at most one value. * This implementation accepts any kind of objects as keys.</p> * * <p>The default factory function should return a new object of the provided * type. Example:</p> * <pre> * function petFactory() { * return new Pet(); * } * </pre> * * <p>If the keys are custom objects a function which converts keys to unique * strings must be provided. Example:</p> * <pre> * function petToString(pet) { * return pet.name; * } * </pre> * @constructor * @param {function():V=} defaultFactoryFunction function used to create a * default object. * @param {function(Object):string=} toStrFunction optional function used * to convert keys to strings. If the keys aren't strings or if toString() * is not appropriate, a custom function which receives a key and returns a * unique string must be provided. */ function FactoryDictionary(defaultFactoryFunction, toStrFunction) { var _this = _super.call(this, toStrFunction) || this; _this.defaultFactoryFunction = defaultFactoryFunction; return _this; } /** * Associates the specified default value with the specified key in this dictionary, * if it didn't contain the key yet. If the key existed, the existing value will be used. * @param {Object} key key with which the specified value is to be * associated. * @param {Object} defaultValue default value to be associated with the specified key. * @return {*} previous value associated with the specified key, or the default value, * if the key didn't exist yet. */ FactoryDictionary.prototype.setDefault = function (key, defaultValue) { var currentValue = _super.prototype.getValue.call(this, key); if (util.isUndefined(currentValue)) { this.setValue(key, defaultValue); return defaultValue; } return currentValue; }; /** * Returns the value to which this dictionary maps the specified key. * Returns a default value created by the factory passed in the constructor, * if this dictionary contains no mapping for this key. The missing key will * automatically be added to the dictionary. * @param {Object} key key whose associated value is to be returned. * @return {*} the value to which this dictionary maps the specified key or * a default value if the map contains no mapping for this key. */ FactoryDictionary.prototype.getValue = function (key) { return this.setDefault(key, this.defaultFactoryFunction()); }; return FactoryDictionary; }(Dictionary_1.default)); exports.default = FactoryDictionary; },{"./Dictionary":4,"./util":16}],6:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var collections = require("./util"); var arrays = require("./arrays"); var Heap = /** @class */ (function () { /** * Creates an empty Heap. * @class * <p>A heap is a binary tree, where the nodes maintain the heap property: * each node is smaller than each of its children and therefore a MinHeap * This implementation uses an array to store elements.</p> * <p>If the inserted elements are custom objects a compare function must be provided, * at construction time, otherwise the <=, === and >= operators are * used to compare elements. Example:</p> * * <pre> * function compare(a, b) { * if (a is less than b by some ordering criterion) { * return -1; * } if (a is greater than b by the ordering criterion) { * return 1; * } * // a must be equal to b * return 0; * } * </pre> * * <p>If a Max-Heap is wanted (greater elements on top) you can a provide a * reverse compare function to accomplish that behavior. Example:</p> * * <pre> * function reverseCompare(a, b) { * if (a is less than b by some ordering criterion) { * return 1; * } if (a is greater than b by the ordering criterion) { * return -1; * } * // a must be equal to b * return 0; * } * </pre> * * @constructor * @param {function(Object,Object):number=} compareFunction optional * function used to compare two elements. Must return a negative integer, * zero, or a positive integer as the first argument is less than, equal to, * or greater than the second. */ function Heap(compareFunction) { /** * Array used to store the elements of the heap. * @type {Array.<Object>} * @private */ this.data = []; this.compare = compareFunction || collections.defaultCompare; } /** * Returns the index of the left child of the node at the given index. * @param {number} nodeIndex The index of the node to get the left child * for. * @return {number} The index of the left child. * @private */ Heap.prototype.leftChildIndex = function (nodeIndex) { return (2 * nodeIndex) + 1; }; /** * Returns the index of the right child of the node at the given index. * @param {number} nodeIndex The index of the node to get the right child * for. * @return {number} The index of the right child. * @private */ Heap.prototype.rightChildIndex = function (nodeIndex) { return (2 * nodeIndex) + 2; }; /** * Returns the index of the parent of the node at the given index. * @param {number} nodeIndex The index of the node to get the parent for. * @return {number} The index of the parent. * @private */ Heap.prototype.parentIndex = function (nodeIndex) { return Math.floor((nodeIndex - 1) / 2); }; /** * Returns the index of the smaller child node (if it exists). * @param {number} leftChild left child index. * @param {number} rightChild right child index. * @return {number} the index with the minimum value or -1 if it doesn't * exists. * @private */ Heap.prototype.minIndex = function (leftChild, rightChild) { if (rightChild >= this.data.length) { if (leftChild >= this.data.length) { return -1; } else { return leftChild; } } else { if (this.compare(this.data[leftChild], this.data[rightChild]) <= 0) { return leftChild; } else { return rightChild; } } }; /** * Moves the node at the given index up to its proper place in the heap. * @param {number} index The index of the node to move up. * @private */ Heap.prototype.siftUp = function (index) { var parent = this.parentIndex(index); while (index > 0 && this.compare(this.data[parent], this.data[index]) > 0) { arrays.swap(this.data, parent, index); index = parent; parent = this.parentIndex(index); } }; /** * Moves the node at the given index down to its proper place in the heap. * @param {number} nodeIndex The index of the node to move down. * @private */ Heap.prototype.siftDown = function (nodeIndex) { //smaller child index var min = this.minIndex(this.leftChildIndex(nodeIndex), this.rightChildIndex(nodeIndex)); while (min >= 0 && this.compare(this.data[nodeIndex], this.data[min]) > 0) { arrays.swap(this.data, min, nodeIndex); nodeIndex = min; min = this.minIndex(this.leftChildIndex(nodeIndex), this.rightChildIndex(nodeIndex)); } }; /** * Retrieves but does not remove the root element of this heap. * @return {*} The value at the root of the heap. Returns undefined if the * heap is empty. */ Heap.prototype.peek = function () { if (this.data.length > 0) { return this.data[0]; } else { return undefined; } }; /** * Adds the given element into the heap. * @param {*} element the element. * @return true if the element was added or fals if it is undefined. */ Heap.prototype.add = function (element) { if (collections.isUndefined(element)) { return false; } this.data.push(element); this.siftUp(this.data.length - 1); return true; }; /** * Retrieves and removes the root element of this heap. * @return {*} The value removed from the root of the heap. Returns * undefined if the heap is empty. */ Heap.prototype.removeRoot = function () { if (this.data.length > 0) { var obj = this.data[0]; this.data[0] = this.data[this.data.length - 1]; this.data.splice(this.data.length - 1, 1); if (this.data.length > 0) { this.siftDown(0); } return obj; } return undefined; }; /** * Returns true if this heap contains the specified element. * @param {Object} element element to search for. * @return {boolean} true if this Heap contains the specified element, false * otherwise. */ Heap.prototype.contains = function (element) { var equF = collections.compareToEquals(this.compare); return arrays.contains(this.data, element, equF); }; /** * Returns the number of elements in this heap. * @return {number} the number of elements in this heap. */ Heap.prototype.size = function () { return this.data.length; }; /** * Checks if this heap is empty. * @return {boolean} true if and only if this heap contains no items; false * otherwise. */ Heap.prototype.isEmpty = function () { return this.data.length <= 0; }; /** * Removes all of the elements from this heap. */ Heap.prototype.clear = function () { this.data.length = 0; }; /** * Executes the provided function once for each element present in this heap in * no particular order. * @param {function(Object):*} callback function to execute, it is * invoked with one argument: the element value, to break the iteration you can * optionally return false. */ Heap.prototype.forEach = function (callback) { arrays.forEach(this.data, callback); }; return Heap; }()); exports.default = Heap; },{"./arrays":15,"./util":16}],7:[function(require,module,exports){ "use strict"; var __extends = (this && this.__extends) || (function () { var extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); Object.defineProperty(exports, "__esModule", { value: true }); var Dictionary_1 = require("./Dictionary"); var util = require("./util"); /** * This class is used by the LinkedDictionary Internally * Has to be a class, not an interface, because it needs to have * the 'unlink' function defined. */ var LinkedDictionaryPair = /** @class */ (function () { function LinkedDictionaryPair(key, value) { this.key = key; this.value = value; } LinkedDictionaryPair.prototype.unlink = function () { this.prev.next = this.next; this.next.prev = this.prev; }; return LinkedDictionaryPair; }()); /** * The head and tail elements of the list have null key and value properties but they * usually link to normal nodes. */ var HeadOrTailLinkedDictionaryPair = /** @class */ (function () { function HeadOrTailLinkedDictionaryPair() { this.key = null; this.value = null; } HeadOrTailLinkedDictionaryPair.prototype.unlink = function () { this.prev.next = this.next; this.next.prev = this.prev; }; return HeadOrTailLinkedDictionaryPair; }()); function isHeadOrTailLinkedDictionaryPair(p) { return !p.next; } var LinkedDictionary = /** @class */ (function (_super) { __extends(LinkedDictionary, _super); function LinkedDictionary(toStrFunction) { var _this = _super.call(this, toStrFunction) || this; _this.head = new HeadOrTailLinkedDictionaryPair(); _this.tail = new HeadOrTailLinkedDictionaryPair(); _this.head.next = _this.tail; _this.tail.prev = _this.head; return _this; } /** * Inserts the new node to the 'tail' of the list, updating the * neighbors, and moving 'this.tail' (the End of List indicator) that * to the end. */ LinkedDictionary.prototype.appendToTail = function (entry) { var lastNode = this.tail.prev; lastNode.next = entry; entry.prev = lastNode; entry.next = this.tail; this.tail.prev = entry; }; /** * Retrieves a linked dictionary from the table internally */ LinkedDictionary.prototype.getLinkedDictionaryPair = function (key) { if (util.isUndefined(key)) { return undefined; } var k = '$' + this.toStr(key); var pair = (this.table[k]); return pair; }; /** * Returns the value to which this dictionary maps the specified key. * Returns undefined if this dictionary contains no mapping for this key. * @param {Object} key key whose associated value is to be returned. * @return {*} the value to which this dictionary maps the specified key or * undefined if the map contains no mapping for this key. */ LinkedDictionary.prototype.getValue = function (key) { var pair = this.getLinkedDictionaryPair(key); if (!util.isUndefined(pair)) { return pair.value; } return undefined; }; /** * Removes the mapping for this key from this dictionary if it is present. * Also, if a value is present for this key, the entry is removed from the * insertion ordering. * @param {Object} key key whose mapping is to be removed from the * dictionary. * @return {*} previous value associated with specified key, or undefined if * there was no mapping for key. */ LinkedDictionary.prototype.remove = function (key) { var pair = this.getLinkedDictionaryPair(key); if (!util.isUndefined(pair)) { _super.prototype.remove.call(this, key); // This will remove it from the table pair.unlink(); // This will unlink it from the chain return pair.value; } return undefined; }; /** * Removes all mappings from this LinkedDictionary. * @this {collections.LinkedDictionary} */ LinkedDictionary.prototype.clear = function () { _super.prototype.clear.call(this); this.head.next = this.tail; this.tail.prev = this.head; }; /** * Internal function used when updating an existing KeyValue pair. * It places the new value indexed by key into the table, but maintains * its place in the linked ordering. */ LinkedDictionary.prototype.replace = function (oldPair, newPair) { var k = '$' + this.toStr(newPair.key); // set the new Pair's links to existingPair's links newPair.next = oldPair.next; newPair.prev = oldPair.prev; // Delete Existing Pair from the table, unlink it from chain. // As a result, the nElements gets decremented by this operation this.remove(oldPair.key); // Link new Pair in place of where oldPair was, // by pointing the old pair's neighbors to it. newPair.prev.next = newPair; newPair.next.prev = newPair; this.table[k] = newPair; // To make up for the fact that the number of elements was decremented, // We need to increase it by one. ++this.nElements; }; /** * Associates the specified value with the specified key in this dictionary. * If the dictionary previously contained a mapping for this key, the old * value is replaced by the specified value. * Updating of a key that already exists maintains its place in the * insertion order into the map. * @param {Object} key key with which the specified value is to be * associated. * @param {Object} value value to be associated with the specified key. * @return {*} previous value associated with the specified key, or undefined if * there was no mapping for the key or if the key/value are undefined. */ LinkedDictionary.prototype.setValue = function (key, value) { if (util.isUndefined(key) || util.isUndefined(value)) { return undefined; } var existingPair = this.getLinkedDictionaryPair(key); var newPair = new LinkedDictionaryPair(key, value); var k = '$' + this.toStr(key); // If there is already an element for that key, we // keep it's place in the LinkedList if (!util.isUndefined(existingPair)) { this.replace(existingPair, newPair); return existingPair.value; } else { this.appendToTail(newPair); this.table[k] = newPair; ++this.nElements; return undefined; } }; /** * Returns an array containing all of the keys in this LinkedDictionary, ordered * by insertion order. * @return {Array} an array containing all of the keys in this LinkedDictionary, * ordered by insertion order. */ LinkedDictionary.prototype.keys = function () { var array = []; this.forEach(function (key, value) { array.push(key); }); return array; }; /** * Returns an array containing all of the values in this LinkedDictionary, ordered by * insertion order. * @return {Array} an array containing all of the values in this LinkedDictionary, * ordered by insertion order. */ LinkedDictionary.prototype.values = function () { var array = []; this.forEach(function (key, value) { array.push(value); }); return array; }; /** * Executes the provided function once for each key-value pair * present in this LinkedDictionary. It is done in the order of insertion * into the LinkedDictionary * @param {function(Object,Object):*} callback function to execute, it is * invoked with two arguments: key and value. To break the iteration you can * optionally return false. */ LinkedDictionary.prototype.forEach = function (callback) { var crawlNode = this.head.next; while (!isHeadOrTailLinkedDictionaryPair(crawlNode)) { var ret = callback(crawlNode.key, crawlNode.value); if (ret === false) { return; } crawlNode = crawlNode.next; } }; return LinkedDictionary; }(Dictionary_1.default)); // End of LinkedDictionary exports.default = LinkedDictionary; // /** // * Returns true if this dictionary is equal to the given dictionary. // * Two dictionaries are equal if they contain the same mappings. // * @param {collections.Dictionary} other the other dictionary. // * @param {function(Object,Object):boolean=} valuesEqualFunction optional // * function used to check if two values are equal. // * @return {boolean} true if this dictionary is equal