typescript-ds-lib
Version:
A collection of TypeScript data structure implementations
227 lines • 6.69 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BinarySearchTree = void 0;
const base_collection_1 = require("./base-collection");
class TreeNode {
value;
left;
right;
constructor(value) {
this.value = value;
this.left = null;
this.right = null;
}
}
class BinarySearchTree extends base_collection_1.BaseCollection {
root;
comparator;
nodeCount;
constructor(comparator = (a, b) => a < b) {
super();
this.root = null;
this.comparator = comparator;
this.nodeCount = 0;
}
/**
* Inserts a value into the BST if it doesn't already exist
*/
insert(value) {
const newNode = new TreeNode(value);
if (!this.root) {
this.root = newNode;
this.nodeCount++;
return;
}
let current = this.root;
while (true) {
if (this.comparator(value, current.value)) {
if (current.left === null) {
current.left = newNode;
this.nodeCount++;
break;
}
current = current.left;
}
else if (this.isEqual(value, current.value)) {
return;
}
else {
if (current.right === null) {
current.right = newNode;
this.nodeCount++;
break;
}
current = current.right;
}
}
}
/**
* Searches for a value in the BST. Returns true if found, false otherwise
*/
find(value) {
let current = this.root;
while (current !== null) {
if (this.isEqual(value, current.value)) {
return true;
}
if (this.comparator(value, current.value)) {
current = current.left;
}
else {
current = current.right;
}
}
return false;
}
/**
* Returns the minimum value in the BST, or undefined if tree is empty
*/
min() {
if (!this.root)
return undefined;
let current = this.root;
while (current.left !== null) {
current = current.left;
}
return current.value;
}
/**
* Returns the maximum value in the BST, or undefined if tree is empty
*/
max() {
if (!this.root)
return undefined;
let current = this.root;
while (current.right !== null) {
current = current.right;
}
return current.value;
}
/**
* Removes a value from the BST if it exists
*/
remove(value) {
this.root = this.removeNode(this.root, value);
}
removeNode(node, value) {
if (node === null)
return null;
if (this.comparator(value, node.value)) {
node.left = this.removeNode(node.left, value);
return node;
}
else if (this.comparator(node.value, value)) {
node.right = this.removeNode(node.right, value);
return node;
}
else {
// Node to delete found
this.nodeCount--;
// Case 1: Leaf node
if (node.left === null && node.right === null) {
return null;
}
// Case 2: Node with one child
if (node.left === null)
return node.right;
if (node.right === null)
return node.left;
// Case 3: Node with two children
const minNode = this.findMin(node.right);
node.value = minNode.value;
node.right = this.removeNode(node.right, minNode.value);
this.nodeCount++; // Increment back since the recursive call decremented
return node;
}
}
findMin(node) {
let current = node;
while (current.left !== null) {
current = current.left;
}
return current;
}
isEqual(a, b) {
// Two values are equal if neither is less than the other
return !this.comparator(a, b) && !this.comparator(b, a);
}
/**
* Executes a callback function for each element in the BST in-order traversal
*/
forEach(callback, traversal = 'inorder') {
switch (traversal) {
case 'inorder':
this.inorderTraversal(this.root, callback);
break;
case 'preorder':
this.preorderTraversal(this.root, callback);
break;
case 'postorder':
this.postorderTraversal(this.root, callback);
break;
default:
this.inorderTraversal(this.root, callback);
}
}
inorderTraversal(node, callback) {
if (node === null)
return;
this.inorderTraversal(node.left, callback);
callback(node.value);
this.inorderTraversal(node.right, callback);
}
preorderTraversal(node, callback) {
if (node === null)
return;
callback(node.value);
this.preorderTraversal(node.left, callback);
this.preorderTraversal(node.right, callback);
}
postorderTraversal(node, callback) {
if (node === null)
return;
this.postorderTraversal(node.left, callback);
this.postorderTraversal(node.right, callback);
callback(node.value);
}
/**
* Returns true if the BST is empty, false otherwise
*/
isEmpty() {
return this.root === null;
}
/**
* Removes all nodes from the BST
*/
clear() {
this.root = null;
this.nodeCount = 0;
}
/**
* Returns the number of nodes in the BST.
*/
size() {
return this.nodeCount;
}
/**
* Checks if two BSTs are equal.
*/
equals(other) {
if (!other || !(other instanceof BinarySearchTree))
return false;
if (this.size() !== other.size())
return false;
return this.areTreesEqual(this.root, other.root);
}
areTreesEqual(node1, node2) {
if (node1 === null && node2 === null)
return true;
if (node1 === null || node2 === null)
return false;
return this.isEqual(node1.value, node2.value) &&
this.areTreesEqual(node1.left, node2.left) &&
this.areTreesEqual(node1.right, node2.right);
}
}
exports.BinarySearchTree = BinarySearchTree;
//# sourceMappingURL=binary-search-tree.js.map