Binary Search Tree
A Binary Search Tree (BST) is a hierarchical data structure where each node has at most two children, with all left descendants less than the current node and all right descendants greater than the current node.
Structure
class Node {
constructor(value) {
this.value = value;
this.left = null;
this.right = null;
}
}
class BinarySearchTree {
constructor() {
this.root = null;
}
}
Advantages
- Efficient searching (O(log n) on average)
- Maintains sorted order
- Flexible size
- Supports many operations efficiently
Disadvantages
- Can become unbalanced
- No constant-time operations
- More complex than arrays for simple operations
- Not cache-friendly due to non-contiguous memory storage
Common Operations
- Insert - Add a new value
- Search - Find a value
- Delete - Remove a value
- Traversal - Visit all nodes
- In-order (Left, Root, Right)
- Pre-order (Root, Left, Right)
- Post-order (Left, Right, Root)
Time Complexities
Operation | Average | Worst |
---|---|---|
Access | O(log n) | O(n) |
Search | O(log n) | O(n) |
Insertion | O(log n) | O(n) |
Deletion | O(log n) | O(n) |
Implementation Example
Here's a complete implementation of a Binary Search Tree with common operations:
class Node {
constructor(value) {
this.value = value;
this.left = null;
this.right = null;
}
}
class BinarySearchTree {
constructor() {
this.root = null;
}
// Insert a new value
insert(value) {
const newNode = new Node(value);
if (!this.root) {
this.root = newNode;
return this;
}
let current = this.root;
while (true) {
if (value === current.value) return undefined;
if (value < current.value) {
if (!current.left) {
current.left = newNode;
return this;
}
current = current.left;
} else {
if (!current.right) {
current.right = newNode;
return this;
}
current = current.right;
}
}
}
// Find a value
find(value) {
if (!this.root) return false;
let current = this.root;
while (current) {
if (value === current.value) return true;
if (value < current.value) {
current = current.left;
} else {
current = current.right;
}
}
return false;
}
// In-order traversal
inOrder() {
const data = [];
function traverse(node) {
if (node.left) traverse(node.left);
data.push(node.value);
if (node.right) traverse(node.right);
}
if (this.root) traverse(this.root);
return data;
}
// Pre-order traversal
preOrder() {
const data = [];
function traverse(node) {
data.push(node.value);
if (node.left) traverse(node.left);
if (node.right) traverse(node.right);
}
if (this.root) traverse(this.root);
return data;
}
// Post-order traversal
postOrder() {
const data = [];
function traverse(node) {
if (node.left) traverse(node.left);
if (node.right) traverse(node.right);
data.push(node.value);
}
if (this.root) traverse(this.root);
return data;
}
}
Visual Representation
A binary search tree can be visualized as a hierarchical structure:
8
/ \
3 10
/ \ \
1 6 14
/ \ /
4 7 13
Common Use Cases
-
Database Indexing
- Efficient data retrieval
- Range queries
-
File Systems
- Directory structures
- File organization
-
Applications
- Expression parsers
- Priority queues
- Spell checkers
Practice Problems
To master binary search trees, try solving these common problems:
- Check if a binary tree is a valid BST
- Find the kth smallest element
- Convert sorted array to BST
- Find lowest common ancestor
- Balance an unbalanced BST
- Find closest value in BST
Additional Resources
Comparison with Other Data Structures
BST vs Array
BST Advantages:
- Better search time (O(log n) vs O(n))
- Dynamic size
- Efficient insertion/deletion
Array Advantages:
- Cache-friendly
- Constant-time access
- Simpler implementation
BST vs Hash Table
BST Advantages:
- Ordered data
- Range queries
- No collision handling needed
Hash Table Advantages:
- O(1) average operations
- Simpler implementation
- Better space efficiency