Overview
A binary search tree (BST) is a binary tree with an ordering rule: every value in a node's left subtree is smaller than the node, and every value in its right subtree is larger. That rule lets search, insert, and delete discard one subtree at each step, just like binary search on a sorted array.
Operations cost O(h), where h is the height. A balanced BST has h = O(log n), but inserting sorted data into a plain BST produces a chain with h = n. That is why production systems use self-balancing trees (see Balanced search trees).
Every node is a guess. If the target is smaller you go left, if larger you go right. Each answer throws away an entire half of the remaining possibilities, so a well-shaped tree finds any value in a handful of steps.
When to use it
- You need sorted data with fast inserts and deletes (arrays make inserts O(n)).
- Floor, ceiling, predecessor, successor, or range queries.
- The problem gives a BST and asks to exploit ordering.
- Maintaining an ordered set or map (Java TreeMap / TreeSet).
Problem patterns it solves
Recognize it when: basic BST operations using the ordering rule.
- 700. Search in a Binary Search Tree
- 701. Insert into a Binary Search Tree
- 450. Delete Node in a BST
Recognize it when: check every node lies within (min, max) inherited from ancestors.
- 98. Validate Binary Search Tree
- 1373. Maximum Sum BST in Binary Tree
Recognize it when: kth smallest, two sum in BST, minimum difference.
- 230. Kth Smallest Element in a BST
- 653. Two Sum IV - Input is a BST
- 530. Minimum Absolute Difference in BST
Recognize it when: split point where p and q go different ways.
- 235. Lowest Common Ancestor of a BST
Recognize it when: sorted array or list to a height-balanced BST.
- 108. Convert Sorted Array to Binary Search Tree
- 109. Convert Sorted List to Binary Search Tree
Recognize it when: sum of values in [low, high], trim to a range.
- 938. Range Sum of BST
- 669. Trim a Binary Search Tree
Where it is used in real software
Java TreeMap and TreeSet, C++ std::map and std::set are balanced BSTs (red-black trees) that support floor, ceiling, and ordered iteration.
B-trees generalize BSTs to many keys per node, minimizing disk reads for range queries like WHERE price BETWEEN 10 AND 20.
The Linux Completely Fair Scheduler stores runnable tasks in a red-black tree ordered by virtual runtime and always runs the leftmost task.
Trading engines keep bids and asks in ordered trees to find the best price and match orders.
Key terms
- BST property
- left subtree < node < right subtree, for every node.
- Inorder successor
- The next larger value: the leftmost node of the right subtree.
- Floor / ceiling
- Largest value <= x / smallest value >= x.
- Degenerate tree
- A BST shaped like a linked list, with O(n) operations.
Deleting a node
- 1Find the node
Go left if key < node.val, right if larger.
- 2Case 1: leaf
Remove it by returning null to the parent.
- 3Case 2: one child
Replace the node with its only child.
- 4Case 3: two children
Find the inorder successor (smallest in the right subtree), copy its value into the node, then delete the successor from the right subtree.
Search for 6 and insert 5
BST: 8 (left 3, right 10); 3 (left 1, right 6); 6 (left 4, right 7)
| Step | Current | Comparison | Move |
|---|---|---|---|
| Search 1 | 8 | 6 < 8 | go left |
| Search 2 | 3 | 6 > 3 | go right |
| Search 3 | 6 | 6 = 6 | found |
| Insert 1 | 8 | 5 < 8 | go left |
| Insert 2 | 3 | 5 > 3 | go right |
| Insert 3 | 6 | 5 < 6 | go left |
| Insert 4 | 4 | 5 > 4 | right is null: attach 5 |
NOWStep: Search 1 | Current: 8 | Comparison: 6 < 8 | Move: go left
Each step goes down one level, so the cost is the height of the tree. New values are always inserted as leaves.
Implementation
function searchBST(root, val) { let node = root; while (node && node.val !== val) node = val < node.val ? node.left : node.right; return node;} function insertIntoBST(root, val) { if (!root) return new TreeNode(val); if (val < root.val) root.left = insertIntoBST(root.left, val); else root.right = insertIntoBST(root.right, val); return root;} function deleteNode(root, key) { if (!root) return null; if (key < root.val) root.left = deleteNode(root.left, key); else if (key > root.val) root.right = deleteNode(root.right, key); else { if (!root.left) return root.right; if (!root.right) return root.left; let successor = root.right; while (successor.left) successor = successor.left; root.val = successor.val; root.right = deleteNode(root.right, successor.val); } return root;} // Validate with inherited bounds, not just parent comparisonfunction isValidBST(node, low = -Infinity, high = Infinity) { if (!node) return true; if (node.val <= low || node.val >= high) return false; return isValidBST(node.left, low, node.val) && isValidBST(node.right, node.val, high);} function sortedArrayToBST(nums, lo = 0, hi = nums.length - 1) { if (lo > hi) return null; const mid = (lo + hi) >> 1; return new TreeNode(nums[mid], sortedArrayToBST(nums, lo, mid - 1), sortedArrayToBST(nums, mid + 1, hi));}Complexity and performance
O(log n) balanced, O(n) degenerate.
Sorted output.
Middle element as root, recursively.
Plus O(h) recursion.
Trade-offs
Hash maps are O(1) average but unordered. BSTs are O(log n) but support ordered iteration, floor, ceiling, and range queries.
A sorted array has faster lookups (cache-friendly binary search) but O(n) inserts. A balanced BST has O(log n) inserts.
A plain BST on sorted or adversarial input degrades to O(n). Use a self-balancing tree in production.
Variants and related techniques
AVL and red-black trees keep height O(log n) with rotations.
Store subtree size in each node to answer kth smallest and rank queries in O(log n).
An explicit stack gives amortized O(1) next() in sorted order.
Common mistakes
- Validating only against the parent.
Fix: A node deep in the left subtree must also be smaller than every ancestor it is left of. Pass bounds down.
- Duplicates.
Fix: Decide a rule (go right, or keep a count) and apply it consistently.
- Integer bounds in Java validation.
Fix: Use Long or nullable Integer bounds; node values can equal Integer.MIN_VALUE.
Interview questions
What is the time complexity of BST operations?
O(h). It is O(log n) when the tree is balanced and O(n) in the worst case, such as after inserting sorted keys.
How do you find the kth smallest element efficiently if it is queried often?
Augment each node with its subtree size. At each node compare k with the left subtree size to decide which way to go, giving O(h) per query.
Practice problems
| Problem | Difficulty | What it trains |
|---|---|---|
| 700. Search in a Binary Search Tree | Easy | Ordering rule. |
| 108. Convert Sorted Array to Binary Search Tree | Easy | Balanced construction. |
| 938. Range Sum of BST | Easy | Pruning with bounds. |
| 98. Validate Binary Search Tree | Medium | Inherited bounds. |
| 450. Delete Node in a BST | Medium | Three deletion cases. |
| 235. Lowest Common Ancestor of a BST | Medium | Split point. |