UNPKG

bst-typed

Version:
561 lines (422 loc) 18.9 kB
![NPM](https://img.shields.io/npm/l/bst-typed) ![GitHub top language](https://img.shields.io/github/languages/top/zrwusa/data-structure-typed) ![npm](https://img.shields.io/npm/dw/bst-typed) ![eslint](https://aleen42.github.io/badges/src/eslint.svg) ![npm bundle size](https://img.shields.io/bundlephobia/minzip/bst-typed) ![npm bundle size](https://img.shields.io/bundlephobia/min/bst-typed) ![npm](https://img.shields.io/npm/v/bst-typed) # What ## Brief This is a standalone BST (Binary Search Tree) data structure from the data-structure-typed collection. If you wish to access more data structures or advanced features, you can transition to directly installing the complete [data-structure-typed](https://www.npmjs.com/package/data-structure-typed) package # How ## install ### npm ```bash npm i bst-typed --save ``` ### yarn ```bash yarn add bst-typed ``` ### snippet #### TS ```typescript import {BST, BSTNode} from 'data-structure-typed'; // /* or if you prefer */ import {BST, BSTNode} from 'bst-typed'; const bst = new BST(); bst instanceof BST; // true bst.add(11); bst.add(3); const idsAndValues = [15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5]; bst.addMany(idsAndValues); bst.root instanceof BSTNode; // true if (bst.root) bst.root.id; // 11 bst.size; // 16 bst.has(6); // true const node6 = bst.get(6); node6 && bst.getHeight(6); // 2 node6 && bst.getDepth(6); // 3 const nodeId10 = bst.get(10); nodeId10?.id; // 10 const nodeVal9 = bst.get(9, 'val'); nodeVal9?.id; // 9 const leftMost = bst.getLeftMost(); leftMost?.id; // 1 const node15 = bst.get(15); const minNodeBySpecificNode = node15 && bst.getLeftMost(node15); minNodeBySpecificNode?.id; // 12 const subTreeSum = node15 && bst.subTreeSum(15); subTreeSum; // 70 const lesserSum = bst.lesserSum(10); lesserSum; // 45 node15 instanceof BSTNode; // true const node11 = bst.get(11); node11 instanceof BSTNode; // true const dfsInorderNodes = bst.DFS('in', 'node'); dfsInorderNodes[0].id; // 1 dfsInorderNodes[dfsInorderNodes.length - 1].id; // 16 bst.perfectlyBalance(); bst.isPerfectlyBalanced(); // true const bfsNodesAfterBalanced = bst.BFS('node'); bfsNodesAfterBalanced[0].id; // 8); bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].id; // 16 const removed11 = bst.remove(11, true); removed11 instanceof Array; // true if (removed11[0].deleted) removed11[0].deleted.id; // 11 bst.isAVLBalanced(); // true bst.getHeight(15); // 1 const removed1 = bst.remove(1, true); removed1 instanceof Array; // true if (removed1[0].deleted) removed1[0].deleted.id; // 1 bst.isAVLBalanced(); // true bst.getHeight(); // 4 const removed4 = bst.remove(4, true); removed4 instanceof Array; // true if (removed4[0].deleted) removed4[0].deleted.id; // 4 bst.isAVLBalanced(); // true bst.getHeight(); // 4 const removed10 = bst.remove(10, true); if (removed10[0].deleted) removed10[0].deleted.id; // 10 bst.isAVLBalanced(); // false bst.getHeight(); // 4 const removed15 = bst.remove(15, true); if (removed15[0].deleted) removed15[0].deleted.id; // 15 bst.isAVLBalanced(); // true bst.getHeight(); // 3 const removed5 = bst.remove(5, true); if (removed5[0].deleted) removed5[0].deleted.id; // 5 bst.isAVLBalanced(); // true bst.getHeight(); // 3 const removed13 = bst.remove(13, true); if (removed13[0].deleted) removed13[0].deleted.id; // 13 bst.isAVLBalanced(); // true bst.getHeight(); // 3 const removed3 = bst.remove(3, true); if (removed3[0].deleted) removed3[0].deleted.id; // 3 bst.isAVLBalanced(); // false bst.getHeight(); // 3 const removed8 = bst.remove(8, true); if (removed8[0].deleted) removed8[0].deleted.id; // 8 bst.isAVLBalanced(); // true bst.getHeight(); // 3 const removed6 = bst.remove(6, true); if (removed6[0].deleted) removed6[0].deleted.id; // 6 bst.remove(6, true).length; // 0 bst.isAVLBalanced(); // false bst.getHeight(); // 3 const removed7 = bst.remove(7, true); if (removed7[0].deleted) removed7[0].deleted.id; // 7 bst.isAVLBalanced(); // false bst.getHeight(); // 3 const removed9 = bst.remove(9, true); if (removed9[0].deleted) removed9[0].deleted.id; // 9 bst.isAVLBalanced(); // false bst.getHeight(); // 3 const removed14 = bst.remove(14, true); if (removed14[0].deleted) removed14[0].deleted.id; // 14 bst.isAVLBalanced(); // false bst.getHeight(); // 2 bst.isAVLBalanced(); // false const bfsIDs = bst.BFS(); bfsIDs[0]; // 2 bfsIDs[1]; // 12 bfsIDs[2]; // 16 const bfsNodes = bst.BFS('node'); bfsNodes[0].id; // 2 bfsNodes[1].id; // 12 bfsNodes[2].id; // 16 ``` #### JS ```javascript const {BST, BSTNode} = require('data-structure-typed'); // /* or if you prefer */ const {BST, BSTNode} = require('bst-typed'); const bst = new BST(); bst instanceof BST; // true bst.add(11); bst.add(3); const idsAndValues = [15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5]; bst.addMany(idsAndValues); bst.root instanceof BSTNode; // true if (bst.root) bst.root.id; // 11 bst.size; // 16 bst.has(6); // true const node6 = bst.get(6); node6 && bst.getHeight(6); // 2 node6 && bst.getDepth(6); // 3 const nodeId10 = bst.get(10); nodeId10?.id; // 10 const nodeVal9 = bst.get(9, 'val'); nodeVal9?.id; // 9 const leftMost = bst.getLeftMost(); leftMost?.id; // 1 const node15 = bst.get(15); const minNodeBySpecificNode = node15 && bst.getLeftMost(node15); minNodeBySpecificNode?.id; // 12 const subTreeSum = node15 && bst.subTreeSum(15); subTreeSum; // 70 const lesserSum = bst.lesserSum(10); lesserSum; // 45 node15 instanceof BSTNode; // true const node11 = bst.get(11); node11 instanceof BSTNode; // true const dfsInorderNodes = bst.DFS('in', 'node'); dfsInorderNodes[0].id; // 1 dfsInorderNodes[dfsInorderNodes.length - 1].id; // 16 bst.perfectlyBalance(); bst.isPerfectlyBalanced(); // true const bfsNodesAfterBalanced = bst.BFS('node'); bfsNodesAfterBalanced[0].id; // 8); bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].id; // 16 const removed11 = bst.remove(11, true); removed11 instanceof Array; // true if (removed11[0].deleted) removed11[0].deleted.id; // 11 bst.isAVLBalanced(); // true bst.getHeight(15); // 1 const removed1 = bst.remove(1, true); removed1 instanceof Array; // true if (removed1[0].deleted) removed1[0].deleted.id; // 1 bst.isAVLBalanced(); // true bst.getHeight(); // 4 const removed4 = bst.remove(4, true); removed4 instanceof Array; // true if (removed4[0].deleted) removed4[0].deleted.id; // 4 bst.isAVLBalanced(); // true bst.getHeight(); // 4 const removed10 = bst.remove(10, true); if (removed10[0].deleted) removed10[0].deleted.id; // 10 bst.isAVLBalanced(); // false bst.getHeight(); // 4 const removed15 = bst.remove(15, true); if (removed15[0].deleted) removed15[0].deleted.id; // 15 bst.isAVLBalanced(); // true bst.getHeight(); // 3 const removed5 = bst.remove(5, true); if (removed5[0].deleted) removed5[0].deleted.id; // 5 bst.isAVLBalanced(); // true bst.getHeight(); // 3 const removed13 = bst.remove(13, true); if (removed13[0].deleted) removed13[0].deleted.id; // 13 bst.isAVLBalanced(); // true bst.getHeight(); // 3 const removed3 = bst.remove(3, true); if (removed3[0].deleted) removed3[0].deleted.id; // 3 bst.isAVLBalanced(); // false bst.getHeight(); // 3 const removed8 = bst.remove(8, true); if (removed8[0].deleted) removed8[0].deleted.id; // 8 bst.isAVLBalanced(); // true bst.getHeight(); // 3 const removed6 = bst.remove(6, true); if (removed6[0].deleted) removed6[0].deleted.id; // 6 bst.remove(6, true).length; // 0 bst.isAVLBalanced(); // false bst.getHeight(); // 3 const removed7 = bst.remove(7, true); if (removed7[0].deleted) removed7[0].deleted.id; // 7 bst.isAVLBalanced(); // false bst.getHeight(); // 3 const removed9 = bst.remove(9, true); if (removed9[0].deleted) removed9[0].deleted.id; // 9 bst.isAVLBalanced(); // false bst.getHeight(); // 3 const removed14 = bst.remove(14, true); if (removed14[0].deleted) removed14[0].deleted.id; // 14 bst.isAVLBalanced(); // false bst.getHeight(); // 2 bst.isAVLBalanced(); // false const bfsIDs = bst.BFS(); bfsIDs[0]; // 2 bfsIDs[1]; // 12 bfsIDs[2]; // 16 const bfsNodes = bst.BFS('node'); bfsNodes[0].id; // 2 bfsNodes[1].id; // 12 bfsNodes[2].id; // 16 ``` [//]: # (No deletion!!! Start of Example Replace Section) ### Merge 3 sorted datasets ```typescript const dataset1 = new BST<number, string>([ [1, 'A'], [7, 'G'] ]); const dataset2 = [ [2, 'B'], [6, 'F'] ]; const dataset3 = new BST<number, string>([ [3, 'C'], [5, 'E'], [4, 'D'] ]); // Merge datasets into a single BinarySearchTree const merged = new BST<number, string>(dataset1); merged.addMany(dataset2); merged.merge(dataset3); // Verify merged dataset is in sorted order console.log([...merged.values()]); // ['A', 'B', 'C', 'D', 'E', 'F', 'G'] ``` ### Find elements in a range ```typescript const bst = new BST<number>([10, 5, 15, 3, 7, 12, 18]); console.log(bst.search(new Range(5, 10))); // [5, 7, 10] console.log(bst.rangeSearch([4, 12], node => node.key.toString())); // ['5', '7', '10', '12'] console.log(bst.search(new Range(4, 12, true, false))); // [5, 7, 10] console.log(bst.rangeSearch([15, 20])); // [15, 18] console.log(bst.search(new Range(15, 20, false))); // [18] ``` ### Find lowest common ancestor ```typescript const bst = new BST<number>([20, 10, 30, 5, 15, 25, 35, 3, 7, 12, 18]); // LCA helper function const findLCA = (num1: number, num2: number): number | undefined => { const path1 = bst.getPathToRoot(num1); const path2 = bst.getPathToRoot(num2); // Find the first common ancestor return findFirstCommon(path1, path2); }; function findFirstCommon(arr1: number[], arr2: number[]): number | undefined { for (const num of arr1) { if (arr2.indexOf(num) !== -1) { return num; } } return undefined; } // Assertions console.log(findLCA(3, 10)); // 7 console.log(findLCA(5, 35)); // 15 console.log(findLCA(20, 30)); // 25 ``` [//]: # (No deletion!!! End of Example Replace Section) ## API docs & Examples [API Docs](https://data-structure-typed-docs.vercel.app) [Live Examples](https://vivid-algorithm.vercel.app) <a href="https://github.com/zrwusa/vivid-algorithm" target="_blank">Examples Repository</a> ## Data Structures <table> <thead> <tr> <th>Data Structure</th> <th>Unit Test</th> <th>Performance Test</th> <th>API Docs</th> </tr> </thead> <tbody> <tr> <td>Binary Search Tree (BST)</td> <td><img src="https://raw.githubusercontent.com/zrwusa/assets/master/images/data-structure-typed/assets/tick.svg" alt=""></td> <td><img src="https://raw.githubusercontent.com/zrwusa/assets/master/images/data-structure-typed/assets/tick.svg" alt=""></td> <td><a href="https://data-structure-typed-docs.vercel.app/classes/BST.html"><span>BST</span></a></td> </tr> </tbody> </table> ## Standard library data structure comparison <table> <thead> <tr> <th>Data Structure Typed</th> <th>C++ STL</th> <th>java.util</th> <th>Python collections</th> </tr> </thead> <tbody> <tr> <td>BST&lt;K, V&gt;</td> <td>-</td> <td>-</td> <td>-</td> </tr> </tbody> </table> ## Benchmark [//]: # (No deletion!!! Start of Replace Section) <div class="json-to-html-collapse clearfix 0"> <div class='collapsible level0' ><span class='json-to-html-label'>bst</span></div> <div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>10,000 add randomly</td><td>31.59</td><td>31.66</td><td>2.74e-4</td></tr><tr><td>10,000 add & delete randomly</td><td>74.56</td><td>13.41</td><td>8.32e-4</td></tr><tr><td>10,000 addMany</td><td>29.16</td><td>34.30</td><td>0.00</td></tr><tr><td>10,000 get</td><td>29.24</td><td>34.21</td><td>0.00</td></tr></table></div> </div> [//]: # (No deletion!!! End of Replace Section) ## Built-in classic algorithms <table> <thead> <tr> <th>Algorithm</th> <th>Function Description</th> <th>Iteration Type</th> </tr> </thead> <tbody> <tr> <td>Binary Tree DFS</td> <td>Traverse a binary tree in a depth-first manner, starting from the root node, first visiting the left subtree, and then the right subtree, using recursion. </td> <td>Recursion + Iteration</td> </tr> <tr> <td>Binary Tree BFS</td> <td>Traverse a binary tree in a breadth-first manner, starting from the root node, visiting nodes level by level from left to right. </td> <td>Iteration</td> </tr> <tr> <td>Binary Tree Morris</td> <td>Morris traversal is an in-order traversal algorithm for binary trees with O(1) space complexity. It allows tree traversal without additional stack or recursion. </td> <td>Iteration</td> </tr> </tbody> </table> ## Software Engineering Design Standards <table> <tr> <th>Principle</th> <th>Description</th> </tr> <tr> <td>Practicality</td> <td>Follows ES6 and ESNext standards, offering unified and considerate optional parameters, and simplifies method names.</td> </tr> <tr> <td>Extensibility</td> <td>Adheres to OOP (Object-Oriented Programming) principles, allowing inheritance for all data structures.</td> </tr> <tr> <td>Modularization</td> <td>Includes data structure modularization and independent NPM packages.</td> </tr> <tr> <td>Efficiency</td> <td>All methods provide time and space complexity, comparable to native JS performance.</td> </tr> <tr> <td>Maintainability</td> <td>Follows open-source community development standards, complete documentation, continuous integration, and adheres to TDD (Test-Driven Development) patterns.</td> </tr> <tr> <td>Testability</td> <td>Automated and customized unit testing, performance testing, and integration testing.</td> </tr> <tr> <td>Portability</td> <td>Plans for porting to Java, Python, and C++, currently achieved to 80%.</td> </tr> <tr> <td>Reusability</td> <td>Fully decoupled, minimized side effects, and adheres to OOP.</td> </tr> <tr> <td>Security</td> <td>Carefully designed security for member variables and methods. Read-write separation. Data structure software does not need to consider other security aspects.</td> </tr> <tr> <td>Scalability</td> <td>Data structure software does not involve load issues.</td> </tr> </table>