From b53f54417d49aad3e9541bbbf9c5f64f90e9f89d Mon Sep 17 00:00:00 2001 From: Ashok Dey Date: Mon, 16 Dec 2019 14:48:16 +0530 Subject: [PATCH 1/9] update: BSF for BST --- .../Trees/BinarySearchTree/index.js | 1 + src/_Problems_/bfs-bst/index.js | 32 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 src/_Problems_/bfs-bst/index.js diff --git a/src/_DataStructures_/Trees/BinarySearchTree/index.js b/src/_DataStructures_/Trees/BinarySearchTree/index.js index 5cd24103..a385f858 100644 --- a/src/_DataStructures_/Trees/BinarySearchTree/index.js +++ b/src/_DataStructures_/Trees/BinarySearchTree/index.js @@ -3,6 +3,7 @@ const Node = require('./Node'); class BinarySearchTree { constructor(value) { + if (!value) throw new Error('Root node value required'); this.root = new Node(value); } diff --git a/src/_Problems_/bfs-bst/index.js b/src/_Problems_/bfs-bst/index.js new file mode 100644 index 00000000..49ebb489 --- /dev/null +++ b/src/_Problems_/bfs-bst/index.js @@ -0,0 +1,32 @@ +const BST = require('../../_DataStructures_/Trees/BinarySearchTree'); +const Queue = require('../../_DataStructures_/Queue'); + +function traverseBFS(root) { + let temp = root; + const arr = []; + const nodeQueue = new Queue(); + + if (root === null) { + return arr; + } + + while (temp !== null) { + arr.push(temp.value); + if (temp.leftChild) nodeQueue.enqueue(temp.leftChild); + if (temp.rightChild) nodeQueue.enqueue(temp.rightChild); + temp = nodeQueue.dequeue(); + } + return arr; +} + +const myBST = new BST(51); + +[10, 34, 32, 12, 90, 54, 61, 2, 71, 9].forEach(e => myBST.add(e)); + +const preOrderElements = myBST.traversePreorder(); +const levelOrderElements = traverseBFS(myBST.root); + +// eslint-disable-next-line no-console +console.log(preOrderElements); +// eslint-disable-next-line no-console +console.log(levelOrderElements); From 944f4c60c71ae2bbb7c7fa1c7d64f90c6669454d Mon Sep 17 00:00:00 2001 From: Ashok Dey Date: Mon, 16 Dec 2019 14:56:03 +0530 Subject: [PATCH 2/9] update: re-implementation of Queue, fix in tests --- src/_DataStructures_/Queue/Queue.test.js | 9 --- src/_DataStructures_/Queue/index.js | 72 ++++++++++++------------ 2 files changed, 35 insertions(+), 46 deletions(-) diff --git a/src/_DataStructures_/Queue/Queue.test.js b/src/_DataStructures_/Queue/Queue.test.js index 999883f0..fe1c502a 100644 --- a/src/_DataStructures_/Queue/Queue.test.js +++ b/src/_DataStructures_/Queue/Queue.test.js @@ -69,14 +69,5 @@ describe('Data Structure : Queue', () => { queue.destroy(); expect(queue.length()).toEqual(0); }); - - it('Override and throw error for other LL methods', () => { - expect(() => { queue.addAtBeginning(); }).toThrowError('Not Allowed'); - expect(() => { queue.addAt(); }).toThrowError('Not Allowed'); - expect(() => { queue.removeFromEnd(); }).toThrowError('Not Allowed'); - expect(() => { queue.getLast(); }).toThrowError('Not Allowed'); - expect(() => { queue.getAt(); }).toThrowError('Not Allowed'); - expect(() => { queue.removeAt(); }).toThrowError('Not Allowed'); - }); }); }); diff --git a/src/_DataStructures_/Queue/index.js b/src/_DataStructures_/Queue/index.js index 9056c130..0a0807df 100644 --- a/src/_DataStructures_/Queue/index.js +++ b/src/_DataStructures_/Queue/index.js @@ -1,56 +1,54 @@ -const { LinkedList: SinglyLinkedLists } = require('../LinkedList'); +const { LinkedList: SLL } = require('../LinkedList'); -class Queue extends SinglyLinkedLists { +class Queue { constructor() { - super(); - this.NotAllowed = 'Not Allowed'; + this.data = this.getStorage(); } - enqueue(data) { - return this.addAtEnd(data); + enqueue(element) { + this.data.enqueue(element); } dequeue() { - const node = this.removeFromBeginning(); - return node ? node.data : node; + return this.data.dequeue(); } peek() { - const node = this.getFirst(); - return node ? node.data : node; + return this.data.peek(); } length() { - return this.size; + return this.data.length(); } destroy() { - this.delete(); - } - - /** Override and throw error for other LL methods */ - addAtBeginning() { - throw new Error(this.NotAllowed); - } - - addAt() { - throw new Error(this.NotAllowed); - } - - removeFromEnd() { - throw new Error(this.NotAllowed); - } - - getLast() { - throw new Error(this.NotAllowed); - } - - getAt() { - throw new Error(this.NotAllowed); - } - - removeAt() { - throw new Error(this.NotAllowed); + return this.data.destroy(); + } + + // eslint-disable-next-line class-methods-use-this + getStorage() { + // encapsulating the internal implementation here + const storage = new SLL(); + + return { + enqueue(element) { + return storage.addAtEnd(element); + }, + dequeue() { + const node = storage.removeFromBeginning(); + return node ? node.data : node; + }, + peek() { + const node = storage.getFirst(); + return node ? node.data : node; + }, + length() { + return storage.size; + }, + destroy() { + storage.delete(); + }, + }; } } From 29f1b16e3d51af4f5f09bd841e2a3c907aaf89d3 Mon Sep 17 00:00:00 2001 From: Ashok Dey Date: Mon, 16 Dec 2019 15:29:59 +0530 Subject: [PATCH 3/9] refactor: moved the core logic to Utils for a clean BST class --- .../Trees/BinarySearchTree/index.js | 147 ++---------------- .../Trees/BinarySearchTree/utils.js | 132 ++++++++++++++++ 2 files changed, 144 insertions(+), 135 deletions(-) create mode 100644 src/_DataStructures_/Trees/BinarySearchTree/utils.js diff --git a/src/_DataStructures_/Trees/BinarySearchTree/index.js b/src/_DataStructures_/Trees/BinarySearchTree/index.js index a385f858..f59d1924 100644 --- a/src/_DataStructures_/Trees/BinarySearchTree/index.js +++ b/src/_DataStructures_/Trees/BinarySearchTree/index.js @@ -1,175 +1,52 @@ /* eslint-disable consistent-return */ const Node = require('./Node'); +const BSTUtils = require('./utils'); class BinarySearchTree { constructor(value) { if (!value) throw new Error('Root node value required'); this.root = new Node(value); - } - - insert(root, value) { - if (root === null) { - const newNode = new Node(value); - // eslint-disable-next-line no-param-reassign - root = newNode; - return root; - } - - if (value < root.value) { - // eslint-disable-next-line no-param-reassign - root.leftChild = this.insert(root.leftChild, value); - return root; - } - if (value > root.value) { - // eslint-disable-next-line no-param-reassign - root.rightChild = this.insert(root.rightChild, value); - return root; - } - } - - preorder(root) { - /** returning an array so as to make testing easy */ - let arr = []; - if (root === null) return []; - arr.push(root.value); - - const left = this.preorder(root.leftChild); - arr = [...arr, ...left]; - - const right = this.preorder(root.rightChild); - arr = [...arr, ...right]; - return arr; - } - - inorder(root) { - /** left - root - right */ - if (root === null) return []; - let arr = []; - const left = this.inorder(root.leftChild); - arr = [...left, ...arr]; - - // print root - arr = [...arr, root.value]; - - const right = this.inorder(root.rightChild); - arr = [...arr, ...right]; - return arr; - } - - postorder(root) { - /** left - right - root */ - - if (root === null) return []; - let arr = []; - - const left = this.postorder(root.leftChild); - arr = [...left, ...arr]; - - const right = this.postorder(root.rightChild); - arr = [...arr, ...right]; - - return [...arr, root.value]; - } - - search(root, value) { - if (root === null) return false; - if (value === root.value) return true; - - if (value < root.value) { - return this.search(root.leftChild, value); - } - if (value > root.value) { - return this.search(root.rightChild, value); - } - } - - delete(root, value) { - if (root === null) { - return root; - } - - if (value > root.value) { - // eslint-disable-next-line no-param-reassign - root.rightChild = this.delete(root.rightChild, value); - } else if (value < root.value) { - // eslint-disable-next-line no-param-reassign - root.leftChild = this.delete(root.leftChild, value); - } else { - // found the node - if (root.leftChild === null) { - // there is a right sub-tree - return root.rightChild; - } - if (root.rightChild === null) { - // there is a left sub-tree - return root.leftChild; - } - /** - * the root contain 2 childs, we got 2 options: - * 1. We can either find the Node with minimum value at from the right sub-tree - * 2. Or, we can find the Node with maximum value from the left sub-tree - * - * I'm picking up 1 here - */ - const minRightNode = this.findMinNode(root.rightChild); - // eslint-disable-next-line no-param-reassign - root.value = minRightNode.value; - // eslint-disable-next-line no-param-reassign - root.rightChild = this.delete(root.rightChild, minRightNode.value); - return root; - } - return root; - } - - findMinNode(root) { - /** The minnimum values is the let most leaf node in BST */ - if (root.leftChild === null) return root; - return this.findMinNode(root.leftChild); - } - - findMaxNode(root) { - if (root.rightChild === null) return root; - return this.findMaxNode(root.rightChild); + this.BSTUtils = BSTUtils; } isEmpty() { return this.root === null; } - /** Layered methods to simplify the BST API */ + /** Layered methods to simplify the BST API using utils under the hood */ add(value) { - return this.insert(this.root, value); + return this.BSTUtils.insert(this.root, value); } - traversePreorder() { - return this.preorder(this.root); + preorder() { + return this.BSTUtils.preorder(this.root); } traversePostorder() { - return this.postorder(this.root); + return this.BSTUtils.postorder(this.root); } traverseInorder() { - return this.inorder(this.root); + return this.BSTUtils.inorder(this.root); } searchFor(value) { - return this.search(this.root, value); + return this.BSTUtils.search(this.root, value); } getMinimum() { - const minNode = this.findMinNode(this.root); + const minNode = this.BSTUtils.findMinNode(this.root); return minNode.value; } getMaximum() { - const maxNode = this.findMaxNode(this.root); + const maxNode = this.BSTUtils.findMaxNode(this.root); return maxNode.value; } remove(value) { - this.root = this.delete(this.root, value); + this.root = this.BSTUtils.delete(this.root, value); } } diff --git a/src/_DataStructures_/Trees/BinarySearchTree/utils.js b/src/_DataStructures_/Trees/BinarySearchTree/utils.js new file mode 100644 index 00000000..86d704e6 --- /dev/null +++ b/src/_DataStructures_/Trees/BinarySearchTree/utils.js @@ -0,0 +1,132 @@ +const Node = require('./Node'); + +const utils = { + // eslint-disable-next-line consistent-return + insert(root, value) { + if (root === null) { + const newNode = new Node(value); + // eslint-disable-next-line no-param-reassign + root = newNode; + return root; + } + + if (value < root.value) { + // eslint-disable-next-line no-param-reassign + root.leftChild = this.insert(root.leftChild, value); + return root; + } + if (value > root.value) { + // eslint-disable-next-line no-param-reassign + root.rightChild = this.insert(root.rightChild, value); + return root; + } + }, + + preorder(root) { + /** returning an array so as to make testing easy */ + let arr = []; + if (root === null) return []; + arr.push(root.value); + + const left = this.preorder(root.leftChild); + arr = [...arr, ...left]; + + const right = this.preorder(root.rightChild); + arr = [...arr, ...right]; + return arr; + }, + + inorder(root) { + /** left - root - right */ + if (root === null) return []; + let arr = []; + const left = this.inorder(root.leftChild); + arr = [...left, ...arr]; + + // print root + arr = [...arr, root.value]; + + const right = this.inorder(root.rightChild); + arr = [...arr, ...right]; + return arr; + }, + + postorder(root) { + /** left - right - root */ + + if (root === null) return []; + let arr = []; + + const left = this.postorder(root.leftChild); + arr = [...left, ...arr]; + + const right = this.postorder(root.rightChild); + arr = [...arr, ...right]; + + return [...arr, root.value]; + }, + + search(root, value) { + if (root === null) return false; + if (value === root.value) return true; + + if (value < root.value) { + return this.search(root.leftChild, value); + } + if (value > root.value) { + return this.search(root.rightChild, value); + } + return false; + }, + + delete(root, value) { + if (root === null) { + return root; + } + + if (value > root.value) { + // eslint-disable-next-line no-param-reassign + root.rightChild = this.delete(root.rightChild, value); + } else if (value < root.value) { + // eslint-disable-next-line no-param-reassign + root.leftChild = this.delete(root.leftChild, value); + } else { + // found the node + if (root.leftChild === null) { + // there is a right sub-tree + return root.rightChild; + } + if (root.rightChild === null) { + // there is a left sub-tree + return root.leftChild; + } + /** + * the root contain 2 childs, we got 2 options: + * 1. We can either find the Node with minimum value at from the right sub-tree + * 2. Or, we can find the Node with maximum value from the left sub-tree + * + * I'm picking up 1 here + */ + const minRightNode = this.findMinNode(root.rightChild); + // eslint-disable-next-line no-param-reassign + root.value = minRightNode.value; + // eslint-disable-next-line no-param-reassign + root.rightChild = this.delete(root.rightChild, minRightNode.value); + return root; + } + return root; + }, + + findMinNode(root) { + /** The minnimum values is the let most leaf node in BST */ + if (root.leftChild === null) return root; + return this.findMinNode(root.leftChild); + }, + + findMaxNode(root) { + if (root.rightChild === null) return root; + return this.findMaxNode(root.rightChild); + }, +}; + +module.exports = utils; From dc95e9098011c07451d255d2eaadb39aef180765 Mon Sep 17 00:00:00 2001 From: Ashok Dey Date: Mon, 16 Dec 2019 15:48:50 +0530 Subject: [PATCH 4/9] refactor: move all tests to a single file --- .../BinarySearchTree/bst-insertion.test.js | 68 ------- .../BinarySearchTree/bst-isEmpty.test.js | 18 -- .../BinarySearchTree/bst-maximum.test.js | 18 -- .../BinarySearchTree/bst-minimum.test.js | 18 -- .../Trees/BinarySearchTree/bst-remove.test.js | 32 ---- .../Trees/BinarySearchTree/bst-search.test.js | 17 -- .../BinarySearchTree/bst-traversals.test.js | 34 ---- .../Trees/BinarySearchTree/bst.test.js | 170 ++++++++++++++++++ .../height-of-bst/height-of-bst.test.js | 6 +- .../BinarySearchTree/height-of-bst/index.js | 2 +- .../Trees/BinarySearchTree/index.js | 12 +- .../Trees/BinaryTree/index.js | 8 +- src/_Problems_/bfs-bst/index.js | 2 +- 13 files changed, 185 insertions(+), 220 deletions(-) delete mode 100644 src/_DataStructures_/Trees/BinarySearchTree/bst-insertion.test.js delete mode 100644 src/_DataStructures_/Trees/BinarySearchTree/bst-isEmpty.test.js delete mode 100644 src/_DataStructures_/Trees/BinarySearchTree/bst-maximum.test.js delete mode 100644 src/_DataStructures_/Trees/BinarySearchTree/bst-minimum.test.js delete mode 100644 src/_DataStructures_/Trees/BinarySearchTree/bst-remove.test.js delete mode 100644 src/_DataStructures_/Trees/BinarySearchTree/bst-search.test.js delete mode 100644 src/_DataStructures_/Trees/BinarySearchTree/bst-traversals.test.js create mode 100644 src/_DataStructures_/Trees/BinarySearchTree/bst.test.js diff --git a/src/_DataStructures_/Trees/BinarySearchTree/bst-insertion.test.js b/src/_DataStructures_/Trees/BinarySearchTree/bst-insertion.test.js deleted file mode 100644 index 8ada776d..00000000 --- a/src/_DataStructures_/Trees/BinarySearchTree/bst-insertion.test.js +++ /dev/null @@ -1,68 +0,0 @@ -const BinarySearchTree = require('./index'); - -describe('Binary Search Tree', () => { - let bst; - let rootsLeftChild; - let rootsRightChild; - let rootsLeftChildsLeftChild; - let rootsLeftChildsRightChild; - let rootsRightChildsLeftChild; - let rootsRightChildsRightChild; - - describe('Creates a binary search tree', () => { - it('should create a bst with root 100', () => { - bst = new BinarySearchTree(100); - expect(bst.root.value).toEqual(100); - }); - - it('should add element 20 to the left of root node', () => { - bst.add(20); - rootsLeftChild = bst.root.leftChild; - expect(rootsLeftChild.value).toEqual(20); - }); - - it('should add element 500 to the right of root node', () => { - bst.add(500); - rootsRightChild = bst.root.rightChild; - expect(rootsRightChild.value).toEqual(500); - }); - - it('should add element 10 to the left of root"s left child', () => { - bst.add(10); - rootsLeftChildsLeftChild = bst.root.leftChild.leftChild; - expect(rootsLeftChildsLeftChild.value).toEqual(10); - }); - - it('should add element 30 to the right of root"s left child', () => { - bst.add(30); - rootsLeftChildsRightChild = bst.root.leftChild.rightChild; - expect(rootsLeftChildsRightChild.value).toEqual(30); - }); - - it('should add element 400 to the left of root"s right child', () => { - bst.add(400); - rootsRightChildsLeftChild = bst.root.rightChild.leftChild; - expect(rootsRightChildsLeftChild.value).toEqual(400); - }); - - it('should add element 600 to the right of root"s right child', () => { - bst.add(600); - rootsRightChildsRightChild = bst.root.rightChild.rightChild; - expect(rootsRightChildsRightChild.value).toEqual(600); - }); - }); - - describe('Check insertion was as expected', () => { - it('Inorder traversal of the created bst should be [ 10, 20, 30, 100, 400, 500, 600 ]', () => { - expect(bst.traverseInorder()).toEqual([10, 20, 30, 100, 400, 500, 600]); - }); - - it('Preorder traversal of the created bst should be [ 100, 20, 10, 30, 500, 400, 600 ]', () => { - expect(bst.traversePreorder()).toEqual([100, 20, 10, 30, 500, 400, 600]); - }); - - it('Postorder traversal of the created bst should be [ 10, 30, 20, 400, 600, 500, 100 ]', () => { - expect(bst.traversePostorder()).toEqual([10, 30, 20, 400, 600, 500, 100]); - }); - }); -}); diff --git a/src/_DataStructures_/Trees/BinarySearchTree/bst-isEmpty.test.js b/src/_DataStructures_/Trees/BinarySearchTree/bst-isEmpty.test.js deleted file mode 100644 index ec81fc88..00000000 --- a/src/_DataStructures_/Trees/BinarySearchTree/bst-isEmpty.test.js +++ /dev/null @@ -1,18 +0,0 @@ -const BinarySearchTree = require('./index'); - -describe('Binary Search Tree', () => { - describe('Is Empty', () => { - const bst = new BinarySearchTree(6); - const keys = [4, 9, 2, 5, 8, 12]; - keys.forEach(el => bst.add(el)); - it('should return False when BST is not empty', () => { - expect(bst.isEmpty()).toEqual(false); - }); - - it('should return True when BST is empty', () => { - keys.push(6); - keys.forEach(el => bst.remove(el)); - expect(bst.isEmpty()).toEqual(true); - }); - }); -}); diff --git a/src/_DataStructures_/Trees/BinarySearchTree/bst-maximum.test.js b/src/_DataStructures_/Trees/BinarySearchTree/bst-maximum.test.js deleted file mode 100644 index f00d0f5b..00000000 --- a/src/_DataStructures_/Trees/BinarySearchTree/bst-maximum.test.js +++ /dev/null @@ -1,18 +0,0 @@ -const BinarySearchTree = require('./index'); - -describe('Binary Search Tree', () => { - describe('Find maximum value in BST', () => { - const bst = new BinarySearchTree(6); - const keys = [4, 9, 2, 5, 8, 12]; - keys.forEach(el => bst.add(el)); - - it('It should expect maximum key', () => { - expect(bst.getMaximum()).toEqual(12); - }); - - it('It should expect new maximum key added in BST', () => { - bst.add(20); - expect(bst.getMaximum()).toEqual(20); - }); - }); -}); diff --git a/src/_DataStructures_/Trees/BinarySearchTree/bst-minimum.test.js b/src/_DataStructures_/Trees/BinarySearchTree/bst-minimum.test.js deleted file mode 100644 index 80793665..00000000 --- a/src/_DataStructures_/Trees/BinarySearchTree/bst-minimum.test.js +++ /dev/null @@ -1,18 +0,0 @@ -const BinarySearchTree = require('./index'); - -describe('Binary Search Tree', () => { - describe('It should Find the minimum value in BST', () => { - const bst = new BinarySearchTree(6); - const keys = [4, 9, 2, 5, 8, 12]; - keys.forEach(el => bst.add(el)); - - it('It should expect minimum key', () => { - expect(bst.getMinimum()).toEqual(2); - }); - - it('It should expect new minimum key added to BST', () => { - bst.add(1); - expect(bst.getMinimum()).toEqual(1); - }); - }); -}); diff --git a/src/_DataStructures_/Trees/BinarySearchTree/bst-remove.test.js b/src/_DataStructures_/Trees/BinarySearchTree/bst-remove.test.js deleted file mode 100644 index b357f82d..00000000 --- a/src/_DataStructures_/Trees/BinarySearchTree/bst-remove.test.js +++ /dev/null @@ -1,32 +0,0 @@ -const BST = require('.'); - -describe('Data Structure : Binary Search Tree', () => { - it('Binary Search Tree should be a Class', () => { - expect(typeof BST.prototype.constructor).toEqual('function'); - }); - - describe('Binary Search Tree API', () => { - let bst = null; - - beforeEach(() => { - bst = new BST(5); - }); - - it('Should delete() an element from Binary Search Tree', () => { - bst.add(4); - bst.add(9); - bst.add(2); - bst.delete(bst.root, 4); - expect(bst.traverseInorder()).toEqual([2, 5, 9]); - bst.delete(bst.root, 2); - expect(bst.traverseInorder()).toEqual([5, 9]); - }); - - it('Should return NULL if root is empty', () => { - const bst2 = new BST(6); - bst2.remove(6); - bst2.remove(9); - expect(bst2.root).toEqual(null); - }); - }); -}); diff --git a/src/_DataStructures_/Trees/BinarySearchTree/bst-search.test.js b/src/_DataStructures_/Trees/BinarySearchTree/bst-search.test.js deleted file mode 100644 index 2558d0a6..00000000 --- a/src/_DataStructures_/Trees/BinarySearchTree/bst-search.test.js +++ /dev/null @@ -1,17 +0,0 @@ -const BinarySearchTree = require('./index'); - -describe('Binary Search Tree', () => { - describe('It should Find the key in BST', () => { - const bst = new BinarySearchTree(6); - const keys = [4, 9, 2, 5, 8, 12]; - keys.forEach(el => bst.add(el)); - - it('It should return true for 8', () => { - expect(bst.searchFor(8)).toEqual(true); - }); - - it('It should return false for 100', () => { - expect(bst.searchFor(100)).toEqual(false); - }); - }); -}); diff --git a/src/_DataStructures_/Trees/BinarySearchTree/bst-traversals.test.js b/src/_DataStructures_/Trees/BinarySearchTree/bst-traversals.test.js deleted file mode 100644 index 95a1d980..00000000 --- a/src/_DataStructures_/Trees/BinarySearchTree/bst-traversals.test.js +++ /dev/null @@ -1,34 +0,0 @@ -const BinarySearchTree = require('./index'); - -describe('Binary search tree traversals', () => { - let bst; - let preOrderTraversal, inOrderTraversal, postOrderTraversal; - - describe('Creates BST', () => { - // Creates BST - bst = new BinarySearchTree(6); - bst.add(4); - bst.add(9); - bst.add(2); - bst.add(5); - bst.add(8); - bst.add(12); - }); - - describe('BST traversals', () => { - it('should complete the Preorder traversal for the above created bst', () => { - preOrderTraversal = bst.traversePreorder(); - expect(preOrderTraversal).toEqual([6, 4, 2, 5, 9, 8, 12]); - }); - - it('should complete the Inorder traversal for the above created bst', () => { - inOrderTraversal = bst.traverseInorder(); - expect(inOrderTraversal).toEqual([2, 4, 5, 6, 8, 9, 12]); - }); - - it('should complete the Postorder traversal for the above created bst', () => { - postOrderTraversal = bst.traversePostorder(); - expect(postOrderTraversal).toEqual([2, 5, 4, 8, 12, 9, 6]); - }); - }); -}); diff --git a/src/_DataStructures_/Trees/BinarySearchTree/bst.test.js b/src/_DataStructures_/Trees/BinarySearchTree/bst.test.js new file mode 100644 index 00000000..6e0a7676 --- /dev/null +++ b/src/_DataStructures_/Trees/BinarySearchTree/bst.test.js @@ -0,0 +1,170 @@ +const BinarySearchTree = require('./index'); + +describe('Data Structure : Binary Search Tree', () => { + let bst; + let rootsLeftChild; + let rootsRightChild; + let rootsLeftChildsLeftChild; + let rootsLeftChildsRightChild; + let rootsRightChildsLeftChild; + let rootsRightChildsRightChild; + + it('Binary Search Tree should be a Class', () => { + expect(typeof BinarySearchTree.prototype.constructor).toEqual('function'); + }); + + describe('Creation of BST', () => { + it('Should create a BST with root 100', () => { + bst = new BinarySearchTree(100); + expect(bst.root.value).toEqual(100); + }); + + it('Should add element 20 to the left of root node', () => { + bst.add(20); + rootsLeftChild = bst.root.leftChild; + expect(rootsLeftChild.value).toEqual(20); + }); + + it('Should add element 500 to the right of root node', () => { + bst.add(500); + rootsRightChild = bst.root.rightChild; + expect(rootsRightChild.value).toEqual(500); + }); + + it('Should add element 10 to the left of root"s left child', () => { + bst.add(10); + rootsLeftChildsLeftChild = bst.root.leftChild.leftChild; + expect(rootsLeftChildsLeftChild.value).toEqual(10); + }); + + it('Should add element 30 to the right of root"s left child', () => { + bst.add(30); + rootsLeftChildsRightChild = bst.root.leftChild.rightChild; + expect(rootsLeftChildsRightChild.value).toEqual(30); + }); + + it("Should add element 400 to the left of root's right child", () => { + bst.add(400); + rootsRightChildsLeftChild = bst.root.rightChild.leftChild; + expect(rootsRightChildsLeftChild.value).toEqual(400); + }); + + it("Should add element 600 to the right of root's right child", () => { + bst.add(600); + rootsRightChildsRightChild = bst.root.rightChild.rightChild; + expect(rootsRightChildsRightChild.value).toEqual(600); + }); + }); + + describe('Check insertion was as expected', () => { + it('Inorder traversal of the created bst should be [ 10, 20, 30, 100, 400, 500, 600 ]', () => { + expect(bst.inorder()).toEqual([10, 20, 30, 100, 400, 500, 600]); + }); + + it('Preorder traversal of the created bst should be [ 100, 20, 10, 30, 500, 400, 600 ]', () => { + expect(bst.preorder()).toEqual([100, 20, 10, 30, 500, 400, 600]); + }); + + it('Postorder traversal of the created bst should be [ 10, 30, 20, 400, 600, 500, 100 ]', () => { + expect(bst.postorder()).toEqual([10, 30, 20, 400, 600, 500, 100]); + }); + }); + + describe('Check if BST `Is Empty`', () => { + bst = new BinarySearchTree(6); + const keys = [4, 9, 2, 5, 8, 12]; + keys.forEach(el => bst.add(el)); + it('Should return `false` when BST is not empty', () => { + expect(bst.isEmpty()).toEqual(false); + }); + + it('Should return `true` when BST is empty', () => { + keys.push(6); + keys.forEach(el => bst.remove(el)); + expect(bst.isEmpty()).toEqual(true); + }); + }); + + describe('Find maximum value in BST', () => { + bst = new BinarySearchTree(6); + [4, 9, 2, 5, 8, 12].forEach(el => bst.add(el)); + + it('Should expect maximum key', () => { + expect(bst.getMaximum()).toEqual(12); + }); + + it('Should expect new maximum key added in BST', () => { + bst.add(20); + expect(bst.getMaximum()).toEqual(20); + }); + }); + + describe('Find the minimum value in BST', () => { + bst = new BinarySearchTree(6); + [4, 9, 2, 5, 8, 12].forEach(el => bst.add(el)); + + it('Should expect minimum key', () => { + expect(bst.getMinimum()).toEqual(2); + }); + + it('Should expect new minimum key added to BST', () => { + bst.add(1); + expect(bst.getMinimum()).toEqual(1); + }); + }); + + describe('Remove Node in BST', () => { + bst = null; + + beforeEach(() => { + bst = new BinarySearchTree(5); + }); + + it('Should delete() an element from Binary Search Tree', () => { + bst.add(4); + bst.add(9); + bst.add(2); + bst.delete(bst.root, 4); + expect(bst.inorder()).toEqual([2, 5, 9]); + bst.delete(bst.root, 2); + expect(bst.inorder()).toEqual([5, 9]); + }); + + it('Should return NULL if root is empty', () => { + const bst2 = new BinarySearchTree(6); + bst2.remove(6); + bst2.remove(9); + expect(bst2.root).toEqual(null); + }); + }); + + describe('Search value in BST', () => { + bst = new BinarySearchTree(6); + [4, 9, 2, 5, 8, 12].forEach(el => bst.add(el)); + + it('Should return `true` for 8', () => { + expect(bst.searchFor(8)).toEqual(true); + }); + + it('Should return `false` for 100', () => { + expect(bst.searchFor(100)).toEqual(false); + }); + }); + + describe('Traversals in BST', () => { + it('Should return the `Preorder Traversal` for given BST', () => { + const preOrderTraversal = bst.preorder(); + expect(preOrderTraversal).toEqual([6, 4, 2, 5, 9, 8, 12]); + }); + + it('Should return the `Inorder Traversal` for given BST', () => { + const inOrderTraversal = bst.inorder(); + expect(inOrderTraversal).toEqual([2, 4, 5, 6, 8, 9, 12]); + }); + + it('Should return the `Postorder Traversal` for given BST', () => { + const postOrderTraversal = bst.postorder(); + expect(postOrderTraversal).toEqual([2, 5, 4, 8, 12, 9, 6]); + }); + }); +}); diff --git a/src/_DataStructures_/Trees/BinarySearchTree/height-of-bst/height-of-bst.test.js b/src/_DataStructures_/Trees/BinarySearchTree/height-of-bst/height-of-bst.test.js index 322172c9..f11f9455 100644 --- a/src/_DataStructures_/Trees/BinarySearchTree/height-of-bst/height-of-bst.test.js +++ b/src/_DataStructures_/Trees/BinarySearchTree/height-of-bst/height-of-bst.test.js @@ -15,15 +15,15 @@ describe('Binary search tree traversals', () => { describe('Check bst was created as expected', () => { it('Inorder traversal of the created bst should be [ 2, 4, 5, 6, 8, 9, 12 ]', () => { - expect(bst.traverseInorder()).toEqual([2, 4, 5, 6, 8, 9, 12]); + expect(bst.inorder()).toEqual([2, 4, 5, 6, 8, 9, 12]); }); it('Preorder traversal of the created bst should be [ 6, 4, 2, 5, 9, 8, 12 ]', () => { - expect(bst.traversePreorder()).toEqual([6, 4, 2, 5, 9, 8, 12]); + expect(bst.preorder()).toEqual([6, 4, 2, 5, 9, 8, 12]); }); it('Postorder traversal of the created bst should be [ 2, 5, 4, 8, 12, 9, 6 ]', () => { - expect(bst.traversePostorder()).toEqual([2, 5, 4, 8, 12, 9, 6]); + expect(bst.postorder()).toEqual([2, 5, 4, 8, 12, 9, 6]); }); }); diff --git a/src/_DataStructures_/Trees/BinarySearchTree/height-of-bst/index.js b/src/_DataStructures_/Trees/BinarySearchTree/height-of-bst/index.js index ad4f1ee7..809a6a65 100644 --- a/src/_DataStructures_/Trees/BinarySearchTree/height-of-bst/index.js +++ b/src/_DataStructures_/Trees/BinarySearchTree/height-of-bst/index.js @@ -27,7 +27,7 @@ function findHeightOfBST(root) { // myBST.add(10); // // console.log(myBST.root); -// console.log(myBST.traversePreorder()); +// console.log(myBST.preorder()); // console.log(findHeightOfBST(myBST.root)); module.exports = findHeightOfBST; diff --git a/src/_DataStructures_/Trees/BinarySearchTree/index.js b/src/_DataStructures_/Trees/BinarySearchTree/index.js index f59d1924..b2ee1924 100644 --- a/src/_DataStructures_/Trees/BinarySearchTree/index.js +++ b/src/_DataStructures_/Trees/BinarySearchTree/index.js @@ -23,11 +23,11 @@ class BinarySearchTree { return this.BSTUtils.preorder(this.root); } - traversePostorder() { + postorder() { return this.BSTUtils.postorder(this.root); } - traverseInorder() { + inorder() { return this.BSTUtils.inorder(this.root); } @@ -61,13 +61,13 @@ class BinarySearchTree { // console.log(bst.root); -// const preorder = bst.traversePreorder(); +// const preorder = bst.preorder(); // console.log('Preorder Traversal - ', preorder); -// const inorder = bst.traverseInorder(); +// const inorder = bst.inorder(); // console.log('Inorder Traversal - ', inorder); -// const postorder = bst.traversePostorder(); +// const postorder = bst.postorder(); // console.log('Postorder Traversal - ', postorder); // const search = 18; @@ -80,7 +80,7 @@ class BinarySearchTree { // console.log('Maximum value =>', maxNode); // bst.remove(4); -// console.log(bst.traversePreorder()); +// console.log(bst.preorder()); // console.log(bst.root); diff --git a/src/_DataStructures_/Trees/BinaryTree/index.js b/src/_DataStructures_/Trees/BinaryTree/index.js index 7cb032c4..296e763e 100644 --- a/src/_DataStructures_/Trees/BinaryTree/index.js +++ b/src/_DataStructures_/Trees/BinaryTree/index.js @@ -21,7 +21,7 @@ class BinaryTree { return root; } - traversePreorder(root) { + preorder(root) { let arr = []; if (root === null) return arr; @@ -29,18 +29,18 @@ class BinaryTree { arr.push(root.value); // push left node - const left = this.traversePreorder(root.leftChild); + const left = this.preorder(root.leftChild); arr = [...arr, ...left]; // push right node - const right = this.traversePreorder(root.rightChild); + const right = this.preorder(root.rightChild); arr = [...arr, ...right]; return arr; } preOrder() { - return this.traversePreorder(this.root); + return this.preorder(this.root); } } diff --git a/src/_Problems_/bfs-bst/index.js b/src/_Problems_/bfs-bst/index.js index 49ebb489..263d8290 100644 --- a/src/_Problems_/bfs-bst/index.js +++ b/src/_Problems_/bfs-bst/index.js @@ -23,7 +23,7 @@ const myBST = new BST(51); [10, 34, 32, 12, 90, 54, 61, 2, 71, 9].forEach(e => myBST.add(e)); -const preOrderElements = myBST.traversePreorder(); +const preOrderElements = myBST.preorder(); const levelOrderElements = traverseBFS(myBST.root); // eslint-disable-next-line no-console From d6adc76908de6b20a6c1f6a518ba4c15321d9201 Mon Sep 17 00:00:00 2001 From: Ashok Dey Date: Mon, 16 Dec 2019 16:06:53 +0530 Subject: [PATCH 5/9] fix: test case fix --- .../{bst.test.js => index.test.js} | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) rename src/_DataStructures_/Trees/BinarySearchTree/{bst.test.js => index.test.js} (96%) diff --git a/src/_DataStructures_/Trees/BinarySearchTree/bst.test.js b/src/_DataStructures_/Trees/BinarySearchTree/index.test.js similarity index 96% rename from src/_DataStructures_/Trees/BinarySearchTree/bst.test.js rename to src/_DataStructures_/Trees/BinarySearchTree/index.test.js index 6e0a7676..44f9a101 100644 --- a/src/_DataStructures_/Trees/BinarySearchTree/bst.test.js +++ b/src/_DataStructures_/Trees/BinarySearchTree/index.test.js @@ -71,20 +71,29 @@ describe('Data Structure : Binary Search Tree', () => { }); describe('Check if BST `Is Empty`', () => { - bst = new BinarySearchTree(6); const keys = [4, 9, 2, 5, 8, 12]; - keys.forEach(el => bst.add(el)); + + beforeEach(() => { + bst = new BinarySearchTree(6); + keys.forEach(el => bst.add(el)); + }); + + afterEach(() => { + if (bst.root) bst.root = null; + }); + it('Should return `false` when BST is not empty', () => { expect(bst.isEmpty()).toEqual(false); }); it('Should return `true` when BST is empty', () => { - keys.push(6); - keys.forEach(el => bst.remove(el)); + bst.remove(6); expect(bst.isEmpty()).toEqual(true); }); }); + /* + describe('Find maximum value in BST', () => { bst = new BinarySearchTree(6); [4, 9, 2, 5, 8, 12].forEach(el => bst.add(el)); @@ -167,4 +176,5 @@ describe('Data Structure : Binary Search Tree', () => { expect(postOrderTraversal).toEqual([2, 5, 4, 8, 12, 9, 6]); }); }); + */ }); From 44060dd303f82432d876b0902c7d1ad23adea613 Mon Sep 17 00:00:00 2001 From: Ashok Dey Date: Mon, 16 Dec 2019 16:28:13 +0530 Subject: [PATCH 6/9] fix: before & after blocks added, fix order of execution --- .../Trees/BinarySearchTree/index.js | 2 +- .../Trees/BinarySearchTree/index.test.js | 39 ++++++++----------- .../Trees/BinarySearchTree/utils.js | 2 +- 3 files changed, 19 insertions(+), 24 deletions(-) diff --git a/src/_DataStructures_/Trees/BinarySearchTree/index.js b/src/_DataStructures_/Trees/BinarySearchTree/index.js index b2ee1924..4865bb41 100644 --- a/src/_DataStructures_/Trees/BinarySearchTree/index.js +++ b/src/_DataStructures_/Trees/BinarySearchTree/index.js @@ -31,7 +31,7 @@ class BinarySearchTree { return this.BSTUtils.inorder(this.root); } - searchFor(value) { + search(value) { return this.BSTUtils.search(this.root, value); } diff --git a/src/_DataStructures_/Trees/BinarySearchTree/index.test.js b/src/_DataStructures_/Trees/BinarySearchTree/index.test.js index 44f9a101..5ec92ced 100644 --- a/src/_DataStructures_/Trees/BinarySearchTree/index.test.js +++ b/src/_DataStructures_/Trees/BinarySearchTree/index.test.js @@ -70,7 +70,7 @@ describe('Data Structure : Binary Search Tree', () => { }); }); - describe('Check if BST `Is Empty`', () => { + describe('Check if BST `Is Empty`, find Min & Max in BST', () => { const keys = [4, 9, 2, 5, 8, 12]; beforeEach(() => { @@ -87,16 +87,11 @@ describe('Data Structure : Binary Search Tree', () => { }); it('Should return `true` when BST is empty', () => { - bst.remove(6); + // remove all the nodes + keys.push(6); // head node + keys.forEach(e => bst.remove(e)); expect(bst.isEmpty()).toEqual(true); }); - }); - - /* - - describe('Find maximum value in BST', () => { - bst = new BinarySearchTree(6); - [4, 9, 2, 5, 8, 12].forEach(el => bst.add(el)); it('Should expect maximum key', () => { expect(bst.getMaximum()).toEqual(12); @@ -106,11 +101,6 @@ describe('Data Structure : Binary Search Tree', () => { bst.add(20); expect(bst.getMaximum()).toEqual(20); }); - }); - - describe('Find the minimum value in BST', () => { - bst = new BinarySearchTree(6); - [4, 9, 2, 5, 8, 12].forEach(el => bst.add(el)); it('Should expect minimum key', () => { expect(bst.getMinimum()).toEqual(2); @@ -123,8 +113,6 @@ describe('Data Structure : Binary Search Tree', () => { }); describe('Remove Node in BST', () => { - bst = null; - beforeEach(() => { bst = new BinarySearchTree(5); }); @@ -133,9 +121,9 @@ describe('Data Structure : Binary Search Tree', () => { bst.add(4); bst.add(9); bst.add(2); - bst.delete(bst.root, 4); + bst.remove(4); expect(bst.inorder()).toEqual([2, 5, 9]); - bst.delete(bst.root, 2); + bst.remove(2); expect(bst.inorder()).toEqual([5, 9]); }); @@ -149,18 +137,26 @@ describe('Data Structure : Binary Search Tree', () => { describe('Search value in BST', () => { bst = new BinarySearchTree(6); - [4, 9, 2, 5, 8, 12].forEach(el => bst.add(el)); it('Should return `true` for 8', () => { - expect(bst.searchFor(8)).toEqual(true); + [4, 9, 2, 5, 8, 12].forEach(el => bst.add(el)); + expect(bst.search(8)).toEqual(true); }); it('Should return `false` for 100', () => { - expect(bst.searchFor(100)).toEqual(false); + expect(bst.search(100)).toEqual(false); }); }); describe('Traversals in BST', () => { + beforeEach(() => { + bst = new BinarySearchTree(6); + [4, 9, 2, 5, 8, 12].forEach(el => bst.add(el)); + }); + afterEach(() => { + if (bst.root) bst.root = null; + }); + it('Should return the `Preorder Traversal` for given BST', () => { const preOrderTraversal = bst.preorder(); expect(preOrderTraversal).toEqual([6, 4, 2, 5, 9, 8, 12]); @@ -176,5 +172,4 @@ describe('Data Structure : Binary Search Tree', () => { expect(postOrderTraversal).toEqual([2, 5, 4, 8, 12, 9, 6]); }); }); - */ }); diff --git a/src/_DataStructures_/Trees/BinarySearchTree/utils.js b/src/_DataStructures_/Trees/BinarySearchTree/utils.js index 86d704e6..05115c58 100644 --- a/src/_DataStructures_/Trees/BinarySearchTree/utils.js +++ b/src/_DataStructures_/Trees/BinarySearchTree/utils.js @@ -66,6 +66,7 @@ const utils = { return [...arr, root.value]; }, + // eslint-disable-next-line consistent-return search(root, value) { if (root === null) return false; if (value === root.value) return true; @@ -76,7 +77,6 @@ const utils = { if (value > root.value) { return this.search(root.rightChild, value); } - return false; }, delete(root, value) { From 784046b326046c8af8403ac7e06d26b0859885a5 Mon Sep 17 00:00:00 2001 From: Ashok Dey Date: Mon, 16 Dec 2019 16:32:19 +0530 Subject: [PATCH 7/9] update: light weight BST objects --- .../Trees/BinarySearchTree/index.js | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/_DataStructures_/Trees/BinarySearchTree/index.js b/src/_DataStructures_/Trees/BinarySearchTree/index.js index 4865bb41..9fdc6f6c 100644 --- a/src/_DataStructures_/Trees/BinarySearchTree/index.js +++ b/src/_DataStructures_/Trees/BinarySearchTree/index.js @@ -6,7 +6,6 @@ class BinarySearchTree { constructor(value) { if (!value) throw new Error('Root node value required'); this.root = new Node(value); - this.BSTUtils = BSTUtils; } isEmpty() { @@ -16,37 +15,37 @@ class BinarySearchTree { /** Layered methods to simplify the BST API using utils under the hood */ add(value) { - return this.BSTUtils.insert(this.root, value); + return BSTUtils.insert(this.root, value); } preorder() { - return this.BSTUtils.preorder(this.root); + return BSTUtils.preorder(this.root); } postorder() { - return this.BSTUtils.postorder(this.root); + return BSTUtils.postorder(this.root); } inorder() { - return this.BSTUtils.inorder(this.root); + return BSTUtils.inorder(this.root); } search(value) { - return this.BSTUtils.search(this.root, value); + return BSTUtils.search(this.root, value); } getMinimum() { - const minNode = this.BSTUtils.findMinNode(this.root); + const minNode = BSTUtils.findMinNode(this.root); return minNode.value; } getMaximum() { - const maxNode = this.BSTUtils.findMaxNode(this.root); + const maxNode = BSTUtils.findMaxNode(this.root); return maxNode.value; } remove(value) { - this.root = this.BSTUtils.delete(this.root, value); + this.root = BSTUtils.delete(this.root, value); } } From 8c408725b3be1cf3ceead43dcf1a53f5374fc047 Mon Sep 17 00:00:00 2001 From: Ashok Dey Date: Mon, 16 Dec 2019 18:49:07 +0530 Subject: [PATCH 8/9] fix: using single array instance --- .../Trees/BinarySearchTree/index.js | 8 +-- .../Trees/BinarySearchTree/utils.js | 56 ++++++------------- 2 files changed, 22 insertions(+), 42 deletions(-) diff --git a/src/_DataStructures_/Trees/BinarySearchTree/index.js b/src/_DataStructures_/Trees/BinarySearchTree/index.js index 9fdc6f6c..1f2b07d1 100644 --- a/src/_DataStructures_/Trees/BinarySearchTree/index.js +++ b/src/_DataStructures_/Trees/BinarySearchTree/index.js @@ -19,15 +19,15 @@ class BinarySearchTree { } preorder() { - return BSTUtils.preorder(this.root); + return BSTUtils.preorder(this.root, []); } postorder() { - return BSTUtils.postorder(this.root); + return BSTUtils.postorder(this.root, []); } inorder() { - return BSTUtils.inorder(this.root); + return BSTUtils.inorder(this.root, []); } search(value) { @@ -70,7 +70,7 @@ class BinarySearchTree { // console.log('Postorder Traversal - ', postorder); // const search = 18; -// console.log(`Search for ${search}`, bst.searchFor(search)); +// console.log(`Search for ${search}`, bst.search(search)); // const minNode = bst.getMinimum(); // console.log('Minimum value =>', minNode); diff --git a/src/_DataStructures_/Trees/BinarySearchTree/utils.js b/src/_DataStructures_/Trees/BinarySearchTree/utils.js index 05115c58..a52f9191 100644 --- a/src/_DataStructures_/Trees/BinarySearchTree/utils.js +++ b/src/_DataStructures_/Trees/BinarySearchTree/utils.js @@ -22,48 +22,28 @@ const utils = { } }, - preorder(root) { - /** returning an array so as to make testing easy */ - let arr = []; - if (root === null) return []; - arr.push(root.value); - - const left = this.preorder(root.leftChild); - arr = [...arr, ...left]; - - const right = this.preorder(root.rightChild); - arr = [...arr, ...right]; - return arr; + preorder(root, array) { + if (root === null) return array; + array.push(root.value); + this.preorder(root.leftChild, array); + this.preorder(root.rightChild, array); + return array; }, - inorder(root) { - /** left - root - right */ - if (root === null) return []; - let arr = []; - const left = this.inorder(root.leftChild); - arr = [...left, ...arr]; - - // print root - arr = [...arr, root.value]; - - const right = this.inorder(root.rightChild); - arr = [...arr, ...right]; - return arr; + inorder(root, array) { + if (root === null) return array; + this.inorder(root.leftChild, array); + array.push(root.value); + this.inorder(root.rightChild, array); + return array; }, - postorder(root) { - /** left - right - root */ - - if (root === null) return []; - let arr = []; - - const left = this.postorder(root.leftChild); - arr = [...left, ...arr]; - - const right = this.postorder(root.rightChild); - arr = [...arr, ...right]; - - return [...arr, root.value]; + postorder(root, array) { + if (root === null) return array; + this.postorder(root.leftChild, array); + this.postorder(root.rightChild, array); + array.push(root.value); + return array; }, // eslint-disable-next-line consistent-return From fa327edee2ba2bf9d44655bba49e93443ad5d037 Mon Sep 17 00:00:00 2001 From: Ashok Dey Date: Mon, 16 Dec 2019 18:56:18 +0530 Subject: [PATCH 9/9] cleanup --- src/_DataStructures_/Trees/BinarySearchTree/index.js | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/_DataStructures_/Trees/BinarySearchTree/index.js b/src/_DataStructures_/Trees/BinarySearchTree/index.js index 1f2b07d1..1c96ed4f 100644 --- a/src/_DataStructures_/Trees/BinarySearchTree/index.js +++ b/src/_DataStructures_/Trees/BinarySearchTree/index.js @@ -1,4 +1,3 @@ -/* eslint-disable consistent-return */ const Node = require('./Node'); const BSTUtils = require('./utils'); @@ -50,15 +49,7 @@ class BinarySearchTree { } // const bst = new BinarySearchTree(6); -// console.log(bst.root); -// bst.add(4); -// bst.add(9); -// bst.add(2); -// bst.add(5); -// bst.add(8); -// bst.add(12); - -// console.log(bst.root); +// [4, 9, 2, 5, 8, 12].forEach(el => bst.add(el)); // const preorder = bst.preorder(); // console.log('Preorder Traversal - ', preorder);