Binary Search Tree (BST)
Binary Search Tree: The Double-Edged Sword
The Story: The Crossroads
Imagine you are standing at a fork in the road. There is a signpost with a number, say 50.
- You are looking for house number 30.
- The sign says: “Smaller numbers go Left. Bigger numbers go Right.”
So you go Left. You hit another fork with the number 25.
- 30 is bigger than 25. You go Right.
- You arrive at house 30.
This is a Binary Search Tree (BST). It converts the act of “Searching” into a series of simple Yes/No decisions. Instead of walking past 1,000 houses, you only make ~10 decisions.
Why do we need it?
BST is the theoretical foundation for:
- Databases: How do you find a User ID without scanning the whole table?
- Sets/Maps: Storing unique items in sorted order.
- Autocomplete: Though Tries are better, BSTs can handle range queries like “Find all users with age > 18 and < 25.”
How the Algorithm “Thinks”
The algorithm is a Gatekeeper.
- Search: Compare target with current node. If smaller, go left. If larger, go right. If equal, found.
- Insert: Search until you hit a dead end (None). Put the new node there.
- Delete: The tricky part.
- If it’s a leaf: Just snip it off.
- If it has one child: Promote the child.
- If it has two children: Find the “Successor” (the smallest node in the right subtree), replace the target with it, and delete the successor.
Engineering Context: The Fatal Flaw
The BST has an Achilles’ heel: Input Order.
- Scenario A (Random): You insert [5, 3, 7, 2, 4]. The tree is bushy and balanced. Height is . Search is fast.
- Scenario B (Sorted): You insert [1, 2, 3, 4, 5].
- 1 goes to root.
- 2 goes to right of 1.
- 3 goes to right of 2.
- … The tree becomes a Line. Height is . Search is slow ().
This is why raw BSTs are rarely used in production. We use their smarter cousins: AVL or Red-Black Trees.
Implementation (Python)
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def insert(root, val):
if not root:
return TreeNode(val)
if val < root.val:
root.left = insert(root.left, val)
elif val > root.val:
root.right = insert(root.right, val)
return root
def search(root, val):
if not root or root.val == val:
return root
if val < root.val:
return search(root.left, val)
return search(root.right, val)
# Usage
root = None
values = [50, 30, 20, 40, 70, 60, 80]
for v in values:
root = insert(root, v)
result = search(root, 60)
print(f"Found: {result.val if result else 'None'}")Summary
The BST teaches us that structure depends on history. If the data arrives in a good order, the structure is strong. If the data arrives in a bad order, the structure collapses. It reminds us that in engineering, we cannot rely on luck; we need mechanisms (balancing) to enforce order regardless of chaos.
