const COMPARE = {
LESS_THEN: -1,
BIGGER_THEN: 1
};
function defaultCompare(a, b) {
if (a === b) return 0;
return a < b ? COMPARE.LESS_THEN : COMPARE.BIGGER_THEN;
}
class Node {
constructor(key) {
this.key = key;
this.left = null;
this.right = null;
}
}
class BinarySearchTree {
constructor(compareFn = defaultCompare) {
this.compareFn = compareFn;
this.root = null;
}
insert(key) {
if (!this.root) {
this.root = new Node(key);
} else {
this.insertNode(this.root, key);
}
}
insertNode(node, key) {
if (this.compareFn(key, node.key) === COMPARE.LESS_THEN) {
if (!node.left) {
node.left = new Node(key);
} else {
this.insertNode(node.left, key);
}
} else {
if (!node.right) {
node.right = new Node(key);
} else {
this.insertNode(node.right, key);
}
}
}
inOrderTraverse(callback) {
this.inOrderTraverseNode(this.root, callback);
}
inOrderTraverseNode(node, callbackFn) {
if (node) {
this.inOrderTraverseNode(node.left, callbackFn);
callbackFn(node.key);
this.inOrderTraverseNode(node.right, callbackFn);
}
}
min() {
return this.minNode(this.root);
}
minNode(node) {
let current = node;
while (current && current.left) {
current = current.left;
}
return current;
}
max() {
return this.maxNode(this.root);
}
maxNode(node) {
let current = node;
while (current && current.right) {
current = current.right;
}
return current;
}
find(key) {
return this.findNode(this.root, key);
}
findNode(node, key) {
if (!node) return false;
if (this.compareFn(key, node.key) === COMPARE.LESS_THEN) {
return this.findNode(node.left, key);
} else if (this.compareFn(key, node.key) === COMPARE.BIGGER_THEN) {
return this.findNode(node.right, key);
} else {
return true;
}
}
remove(key) {
return this.removeNode(this.root, key);
}
removeNode(node, key) {
if (!node) return null;
if (this.compareFn(key, node.key) === COMPARE.LESS_THEN) {
node.left = this.removeNode(node.left, key);
return node;
} else if (this.compareFn(key, node.key) === COMPARE.BIGGER_THEN) {
node.right = this.removeNode(node.right, key);
return node;
} else {
if (node.left == null && node.right == null) {
node = null;
return node;
}
if (node.left == null) {
node = node.right;
return node;
} else if (node.right == null) {
node = node.left;
return node;
}
const aux = this.minNode(node.right);
node.key = aux.key;
node.right = this.removeNode(node.right, aux.key);
return node;
}
}
}