class Node { value: number; left: Node | null = null; right: Node | null = null; constructor(value: number) { this.value = value; } } class BST { root: Node | null = null; insert(value: number) { const newNode = new Node(value); if (!this.root) { this.root = newNode; return; } let current = this.root; while (true) { if (value < current.value) { if (!current.left) { current.left = newNode; return; } current = current.left; } else { if (!current.right) { current.right = newNode; return; } current = current.right; } } } printInOrder(node: Node | null = this.root): string { if (!node) return ''; const left = this.printInOrder(node.left); const right = this.printInOrder(node.right); return (left ? left + ' -> ' : '') + node.value + (right ? ' -> ' + right : ''); } } const bst = new BST(); bst.insert(10); bst.insert(5); bst.insert(15); bst.insert(3); bst.insert(7); console.log(bst.printInOrder());
In a BST, the in-order traversal visits nodes in ascending order. After inserting 10, 5, 15, 3, and 7, the tree structure ensures the in-order print is sorted: 3 -> 5 -> 7 -> 10 -> 15.
The BST property means left children are smaller and right children are larger than the node. This lets us decide which subtree to search next, cutting the search space roughly in half each step, making search efficient.
insert(value: number) {
const newNode = new Node(value);
if (!this.root) {
this.root = newNode;
return;
}
let current = this.root;
while (true) {
if (value <= current.value) {
if (!current.left) {
current.left = newNode;
return;
}
current = current.left;
} else {
if (!current.right) {
current.right = newNode;
return;
}
current = current.right;
}
}
}Using <= for deciding to go left causes duplicates to always go left. If duplicates already exist on the left, the loop never ends, causing an infinite loop.
class Node { value: number; left: Node | null = null; right: Node | null = null; constructor(value: number) { this.value = value; } } class BST { root: Node | null = null; insert(value: number) { const newNode = new Node(value); if (!this.root) { this.root = newNode; return; } let current = this.root; while (true) { if (value < current.value) { if (!current.left) { current.left = newNode; return; } current = current.left; } else { if (!current.right) { current.right = newNode; return; } current = current.right; } } } findMin(node: Node): Node { while (node.left) { node = node.left; } return node; } delete(value: number, node: Node | null = this.root): Node | null { if (!node) return null; if (value < node.value) { node.left = this.delete(value, node.left); } else if (value > node.value) { node.right = this.delete(value, node.right); } else { if (!node.left) return node.right; if (!node.right) return node.left; const minRight = this.findMin(node.right); node.value = minRight.value; node.right = this.delete(minRight.value, node.right); } return node; } printInOrder(node: Node | null = this.root): string { if (!node) return ''; const left = this.printInOrder(node.left); const right = this.printInOrder(node.right); return (left ? left + ' -> ' : '') + node.value + (right ? ' -> ' + right : ''); } } const bst = new BST(); [20, 10, 30, 5, 15, 25, 35].forEach(v => bst.insert(v)); bst.delete(20); console.log(bst.printInOrder());
When deleting node 20 (root), it is replaced by the minimum node in its right subtree, which is 25. Then 25 is removed from its original position. The in-order traversal reflects this updated tree.
The BST property ensures that for any node, all values in the left subtree are smaller and all in the right subtree are larger. This ordering is what allows efficient binary search-like operations on the tree.