UNPKG

esds

Version:

ES6 JS lightweight data structures (Priority Queue, Binary Search Tree (BST), Graph, Bloom Filters, Trie, Queue, Stack, Linked-List)

358 lines (319 loc) 10.7 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>JSDoc: Source: BST.mjs</title> <script src="scripts/prettify/prettify.js"> </script> <script src="scripts/prettify/lang-css.js"> </script> <!--[if lt IE 9]> <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css"> <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css"> </head> <body> <div id="main"> <h1 class="page-title">Source: BST.mjs</h1> <section> <article> <pre class="prettyprint source linenums"><code>// Constants const IN_ORDER = "in-order"; const PRE_ORDER = "pre-order"; const POST_ORDER = "post-order"; const REV_PRE_ORDER = "reverse-in-order"; const RM_PREDECESSOR = "predecessor"; const RM_SUCCESSOR = "successor"; /** * TreeElement Class * Represents an element of the BST */ class TreeElement { /** * @param {number} key - Unique key for the element * @param {any=} [value] - Value of the element, null if not provided */ constructor(key, value = null) { this.key = key; this.value = value; this.left = null; this.right = null; } } /** * BST Class * Binary Search Tree */ class BST { /** * BST Constructor */ constructor() { this.root = null; this.nodes = 0; } /** * Clears the BST */ clear() { this.root = null; this.nodes = 0; } /** * Insert a new element in the BST * @param {number} key - Unique key for the element * @param {any} [value] - Value of the element, null if not provided * @returns {boolean} - True - If element was added * @throws {Error} - If Element already exists in the BST */ add(key, value = null) { const newNode = new TreeElement(key, value); // If tree is empty, sets new element as tree root if (!this.root) { this.root = newNode; this.nodes++; return true; } const addNode = (current, newNode) => { if (current.key > newNode.key) { if (current.left) addNode(current.left, newNode); else { current.left = newNode; this.nodes++; } } else if (current.key &lt; newNode.key) { if (current.right) addNode(current.right, newNode); else { current.right = newNode; this.nodes++; } } else throw new Error("Node already exists"); }; addNode(this.root, newNode); } /** * Removes an existing element in the BST * @param {number} key - Unique key for the element * @param {string} [type=predecessor] - Specifies delete type, allows 'predecessor' (default) for in-order predecessor, and 'successor' for in-order successor * @returns {boolean} - True - If element was added; False if element does not exists * @throws {Error} - If delete type is invalid */ remove(key, type = RM_PREDECESSOR) { let parent = null; let current = this.root; while (current &amp;&amp; current.key !== key) { parent = current; if (current.key > key) current = current.left; else current = current.right; } if (!current) return false; // Check children if (!current.left &amp;&amp; !current.right) { // No children if (!parent) this.root = null; else if (parent.key > key) parent.left = null; else parent.right = null; this.nodes--; } else if (current.left &amp;&amp; !current.right) { // Left child if (!parent) this.root = current.left; else if (parent.key > key) parent.left = current.left; else parent.right = current.left; this.nodes--; } else if (current.right &amp;&amp; !current.left) { // Right child if (!parent) this.root = current.right; else if (parent.key > key) parent.left = current.right; else parent.right = current.right; this.nodes--; } else { // Both children are present if (type === RM_PREDECESSOR) { // Get Predecessor let { node: predecessor, parent: predecessorParent } = this.#max( current.left, true ); // Swap Predecessor with Current [current.key, predecessor.key, current.value] = [ predecessor.key, current.key, predecessor.value, ]; // Rearrange children if (predecessorParent.key === predecessor.key) { current.left = predecessor.left; } else if (predecessor.left) predecessorParent.right = predecessor.left; else predecessorParent.right = null; this.nodes--; } else if (type === RM_SUCCESSOR) { // Get Successor let { node: successor, parent: successorParent } = this.#min( current.right, true ); // Swap Successor with Current [current.key, successor.key, current.value] = [ successor.key, current.key, successor.value, ]; // Rearrange children if (successorParent.key === successor.key) { current.right = successor.right; } else if (successor.right) successorParent.left = successor.right; else successorParent.left = null; this.nodes--; } else throw new Error("Invalid remove type"); } return true; } /** * Updates an existing element in the BST * @param {number} key - Unique key for the element * @param {any} [value] - Value of the element, null if not provided * @returns {boolean} - True - If element was edited * @throws {Error} - If element is not found */ update(key, value = null) { let current = this.root; while (current &amp;&amp; current.key !== key) { if (current.key > key) current = current.left; else current = current.right; } if (current) { current.value = value; return true; } else throw new Error("Node not found"); } /** * Returns an existing element in the BST * @param {number} [key=null] - Unique key for the element, if null, return root of BST * @returns {TreeElement} - Requested element, root of key is not provided * @throws {Error} - If element is not found */ get(key = null) { if (!key &amp;&amp; key !== 0) return this.root; // If key is not provided return BST root let current = this.root; while (current &amp;&amp; current.key !== key) { if (current.key > key) current = current.left; else current = current.right; } if (current) return current; else throw new Error("Node not found"); } /** * Indicates if an element exists in the BST * @param {number} key - Unique key for the element * @returns {boolean} - True if element exists, false if element does not exists */ has(key) { let current = this.root; while (current &amp;&amp; current.key !== key) { if (current.key > key) current = current.left; else current = current.right; } return current !== null; } /** * Returns an array containing the key of the elements in the BST * @param {number} key - Unique key for the element * @param {string} [traversal="in-order"] - Specifies Traversal type, allows 'in-order' (default), 'pre-order', 'post-order', and 'reverse-in-order * @returns {number[]} - Array of element keys */ toArray(traversal = IN_ORDER, node = this.root, output = []) { if (![IN_ORDER, PRE_ORDER, POST_ORDER, REV_PRE_ORDER].includes(traversal)) throw new Error("Invalid traversal"); if (!node) return null; switch (traversal) { case IN_ORDER: this.toArray(traversal, node.left, output); output.push(node.key); this.toArray(traversal, node.right, output); break; case PRE_ORDER: output.push(node.key); this.toArray(traversal, node.left, output); this.toArray(traversal, node.right, output); break; case POST_ORDER: this.toArray(traversal, node.left, output); this.toArray(traversal, node.right, output); output.push(node.key); break; case REV_PRE_ORDER: this.toArray(traversal, node.right, output); output.push(node.key); this.toArray(traversal, node.left, output); break; } return output; } // Getters /** * Returns max element in the BST * @returns {TreeElement} - Max element, null if BST is empty */ get max() { let node = this.root; while (node.right) node = node.right; return node; } /** * Returns min element in the BST * @returns {TreeElement} - Min element, null if BST is empty */ get min() { let node = this.root; while (node.left) node = node.left; return node; } /** * Returns number of element in the BST * @returns {number} - Number of elements in the BST */ get size() { return this.nodes; } /** * Indicates if the BST is empty * @returns {boolean} - True if BST is empty, false if there's at least one element present */ get isEmpty() { return this.root === null; } // Private // Return Max element from given subtree, returns parent of element if returnParent is set to True #max(node, returnParent = false) { let parent = node; while (node.right) { parent = node; node = node.right; } return returnParent ? { node, parent } : { node, parent: null }; } // Return Min element from given subtree, returns parent of element if returnParent is set to True #min(node, returnParent = false) { let parent = node; while (node.left) { parent = node; node = node.left; } return returnParent ? { node, parent } : { node, parent: null }; } } export { BST }; </code></pre> </article> </section> </div> <nav> <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="BloomFilter.html">BloomFilter</a></li><li><a href="BST.html">BST</a></li><li><a href="Element.html">Element</a></li><li><a href="Graph.html">Graph</a></li><li><a href="List.html">List</a></li><li><a href="Node.html">Node</a></li><li><a href="PriorityQueue.html">PriorityQueue</a></li><li><a href="Queue.html">Queue</a></li><li><a href="Stack.html">Stack</a></li><li><a href="TreeElement.html">TreeElement</a></li><li><a href="Trie.html">Trie</a></li></ul> </nav> <br class="clear"> <footer> Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.7</a> on Thu Sep 23 2021 00:49:18 GMT-0700 (Pacific Daylight Time) </footer> <script> prettyPrint(); </script> <script src="scripts/linenumber.js"> </script> </body> </html>