UNPKG

typescript-collections

Version:

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

416 lines 13.7 kB
"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; //# sourceMappingURL=BSTreeKV.js.map