UNPKG

lgrthms

Version:

Algorithms and data structures for your JavaScript and TypeScript projects 🧑‍💻

246 lines (245 loc) 7.46 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.BinarySearchTree = void 0; const Comparator_1 = require("../utils/Comparator"); class Node { constructor(value) { this.parent = null; this.left = null; this.right = null; this.value = value; } } class BinarySearchTree { constructor(compareFn) { this._root = null; this._size = 0; this.comparator = new Comparator_1.Comparator(compareFn); } get root() { return this._root; } get size() { return this._size; } // Average: O(log(n)) time | O(1) space // Worst: O(n) time | O(1) space insert(value) { const nodeToInsert = new Node(value); if (!this.root) { this._root = nodeToInsert; this._size++; return nodeToInsert; } let current = this._root; while (current) { if (this.comparator.isLessThan(value, current.value)) { if (current.left) { current = current.left; continue; } else { current.left = nodeToInsert; nodeToInsert.parent = current; this._size++; break; } } else { if (current.right) { current = current.right; continue; } else { current.right = nodeToInsert; nodeToInsert.parent = current; this._size++; break; } } } return nodeToInsert; } // Average: O(log(n)) time | O(1) space // Worst: O(n) time | O(1) space remove(node, root = this._root) { if (!root || !this.contains(node, root)) { return; } if (node.left && node.right) { this.removeNodeWithTwoChildren(node); } else if (!node.parent) { this.removeRoot(node); } else { this.removeSingleChildOrLeafNode(node); } this._size--; } // Best: O(log(n)) time | O(1) space // Average: O(log(n)^2) time | O(1) space // Worst: O(n^2) time | O(1) space removeWithValue(target, predicate) { let nodeToRemove = this.findNode(target, predicate); while (nodeToRemove) { this.remove(nodeToRemove, nodeToRemove); nodeToRemove = this.findNode(target, predicate); } } // Average: O(log(n)) time | O(1) space // Worst: O(n) time | O(1) space contains(node, root = this._root) { let current = root; while (current) { if (current === node) { return true; } if (this.comparator.isLessThan(node.value, current.value)) { current = current.left; } else { current = current.right; } } return false; } // Average: O(log(n)) time | O(1) space // Worst: O(n) time | O(1) space findNode(target, predicate) { const isDesiredValue = predicate ? predicate : (value) => value === target; let current = this._root; while (current) { if (isDesiredValue(current.value)) { return current; } if (this.comparator.isLessThan(target, current.value)) { current = current.left; } else { current = current.right; } } } // Average: O(log(n)) time | O(1) space // Worst: O(n) time | O(1) space find(target, predicate) { const node = this.findNode(target, predicate); return node ? node.value : undefined; } // Average: O(log(n)) time | O(1) space // Worst: O(n) time | O(1) space findMinNode(root = this._root) { if (!root) { return; } let current = root; while (current.left) { current = current.left; } return current; } // Average: O(log(n)) time | O(1) space // Worst: O(n) time | O(1) space findMin(root = this._root) { const node = this.findMinNode(root); return node ? node.value : undefined; } // Average: O(log(n)) time | O(1) space // Worst: O(n) time | O(1) space findMaxNode(root = this._root) { if (!root) { return; } let current = root; while (current.right) { current = current.right; } return current; } // Average: O(log(n)) time | O(1) space // Worst: O(n) time | O(1) space findMax(root = this._root) { const node = this.findMaxNode(root); return node ? node.value : undefined; } // O(n) time | O(h) space traverseInOrder(callbackfn, node = this._root) { if (node) { this.traverseInOrder(callbackfn, node.left); callbackfn(node.value); this.traverseInOrder(callbackfn, node.right); } } // O(n) time | O(h) space traversePreOrder(callbackfn, node = this._root) { if (node) { callbackfn(node.value); this.traversePreOrder(callbackfn, node.left); this.traversePreOrder(callbackfn, node.right); } } // O(n) time | O(h) space traversePostOrder(callbackfn, node = this._root) { if (node) { this.traversePostOrder(callbackfn, node.left); this.traversePostOrder(callbackfn, node.right); callbackfn(node.value); } } // Average: O(log(n)) time | O(1) space // Worst: O(n) time | O(1) space removeNodeWithTwoChildren(node) { const nodeToReplaceWith = this.findMinNode(node.right); node.value = nodeToReplaceWith.value; this.removeSingleChildOrLeafNode(nodeToReplaceWith); } // O(1) time | O(1) space removeRoot(node) { if (node.left) { node.value = node.left.value; node.right = node.left.right; node.left = node.left.left; } else if (node.right) { node.value = node.right.value; node.left = node.right.left; node.right = node.right.right; } else { this._root = null; } } // O(1) time | O(1) space removeSingleChildOrLeafNode(node) { if (node.parent.left === node) { if (node.left) { node.parent.left = node.left; node.left.parent = node.parent; } else if (node.right) { node.parent.left = node.right; node.right.parent = node.parent; } else { node.parent.left = null; } } if (node.parent.right === node) { if (node.left) { node.parent.right = node.left; node.left.parent = node.parent; } else if (node.right) { node.parent.right = node.right; node.right.parent = node.parent; } else { node.parent.right = null; } } } } exports.BinarySearchTree = BinarySearchTree;