Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Binary search tree examples are the fastest path from confusion to real confidence with one of computing’s most enduring data structures. Most tutorials show you a five-node diagram, walk through one search operation, and call it done. That’s not enough. Real problems — the kind that appear in interviews and production codebases — involve edge cases, unbalanced trees, and operations that interact in unexpected ways. This guide covers all of it: insertion, deletion, validation, transformation, and the performance trade-offs that determine whether a BST helps or quietly hurts your application. We’ll work through eight progressively challenging binary search tree examples with real, runnable code. By the end, you won’t just understand BSTs — you’ll know exactly when to use them.
📌 Before you continue: If you’re new to algorithmic complexity, read our guide on Big O Notation for Beginners first — it’ll make everything in this article click faster.
Before binary search trees existed, developers had two bad options. Arrays supported fast binary search — O(log n) — but inserting a new element meant shifting every element after it, costing O(n) time. Linked lists handled insertion gracefully at O(1), but searching required scanning every node: O(n). Neither structure handled both operations well.
Binary search tree examples help illustrate exactly why this matters. The BST emerged in the late 1950s and early 1960s as an answer to this tension. The core insight: if a data structure maintained sorted order internally — through its shape rather than manual shifting — you could achieve fast search and fast insertion together. The earliest formal descriptions appear in computing literature from that era, around the same time researchers were developing foundational sorting algorithms.
What’s striking in retrospect is how quickly the balance problem became apparent. AVL trees — the first self-balancing variant — were published by Adelson-Velsky and Landis in 1962, within years of the BST concept being formalized. The pressure to solve imbalance came almost immediately.
A Binary Search Tree is a binary tree where every node satisfies one rule: all values in the left subtree are smaller than the current node, and all values in the right subtree are larger. That’s the entirety of the BST property.
Here’s a minimal node structure in C++:
struct Node {
int data;
Node* left;
Node* right;
Node(int val) : data(val), left(nullptr), right(nullptr) {}
};
When you study binary search tree examples, you’ll notice the same pattern every time: start at root, go left if smaller, go right if larger, stop when equal. Each comparison eliminates roughly half the remaining nodes — at least when the tree is balanced.
One property worth knowing early: an inorder traversal of a BST (left subtree → current node → right subtree) produces all values in ascending sorted order. This follows directly from the BST ordering rule, and it makes many binary search tree examples dramatically simpler to solve.
<!– IMAGE: Insert BST diagram here showing left/right subtree ordering. Alt text: “binary search tree examples diagram showing BST property with left smaller right larger rule” –>
The plain BST is rarely used directly in production today. Its descendants — AVL trees, Red-Black trees, B-Trees — are what power real systems. But understanding binary search tree examples at the base level is essential, because everything built on top either addresses a specific BST weakness or extends a BST strength.
Database indexes are the most visible real-world application. When you run a SQL query like WHERE price BETWEEN 50 AND 200, the database performs a range search on a B-Tree index — a multi-way generalization of BSTs designed for disk-based storage.
For further reading, see the Wikipedia article on Binary Search Trees and the NIST Dictionary of Algorithms and Data Structures.
It’s a fair question: if hash maps offer O(1) average-case lookup, why study binary search tree examples at all? The answer is that hash maps and BSTs solve fundamentally different problems.
Hash maps don’t maintain order. They can’t efficiently answer “find all values between X and Y.” They can’t return results in sorted order without a separate sort step. Binary search tree examples consistently demonstrate this gap — ordered operations are where BSTs win every time.
The data structure powering std::set and std::map in C++ is a Red-Black tree. Java’s TreeMap is a Red-Black tree. Python’s sortedcontainers.SortedList uses a B-tree variant. These aren’t legacy structures — they’re actively used because ordered operations are genuinely common.
| Application Area | How BSTs Are Used | Why Not a Hash Map |
|---|---|---|
| Database indexing | B-Tree indexes for range queries | Hash indexes can’t do range queries |
| In-memory sorted sets | std::set / TreeMap / SortedList | Hash sets are unordered |
| Real-time analytics | Window-based aggregations over sorted streams | Requires ordered traversal |
| Compiler symbol tables | Scope-aware ordered lookup | Predictable worst-case needed |
| Embedded systems | Fixed-memory sorted collections | Hash maps have unpredictable resize cost |
| Autocomplete engines | Prefix trees (a BST cousin) | Prefix matching requires ordered structure |
| ML feature pipelines | Sorted stream processing | Order-dependent aggregations |
Machine learning pipelines, event-driven scheduling systems, and latency-sensitive applications where O(n) worst-case is unacceptable — all of these benefit from understanding binary search tree examples and choosing the right BST variant.
A balanced BST with one million records has height roughly 20 (log₂(1,000,000) ≈ 20). An unbalanced BST built from sorted input degrades to height 1,000,000. Finding a value in the balanced tree: ~20 comparisons. In the degenerate case: up to 1,000,000. That’s five orders of magnitude — not a rounding error.
Binary search tree examples built from sorted data illustrate this worst case immediately. Insert [1, 2, 3, 4, 5] in order and you get a straight line pointing right, with zero branching. Every operation behaves like a linked list scan.
| Operation | Balanced BST | Unbalanced BST | Sorted Array | Hash Map |
|---|---|---|---|---|
| Search | O(log n) | O(n) | O(log n) | O(1) avg |
| Insert | O(log n) | O(n) | O(n) | O(1) avg |
| Delete | O(log n) | O(n) | O(n) | O(1) avg |
| Min / Max | O(log n) | O(n) | O(1) | O(n) |
| Range query | O(log n + k) | O(n) | O(log n + k) | Not supported |
| Inorder traversal | O(n) | O(n) | O(n) | O(n) |
| Nearest value | O(log n) | O(n) | O(log n) | Not supported |
k = number of results in range query
| Property | AVL Tree | Red-Black Tree |
|---|---|---|
| Balance guarantee | Height difference ≤ 1 at every node | Height ≤ 2 log₂(n+1) |
| Lookup speed | Slightly faster (stricter balance) | Slightly slower |
| Insert/delete cost | More rotations required | Fewer rotations |
| Best use case | Read-heavy workloads | Write-heavy workloads |
| Common usage | AVL-based databases | std::map, TreeMap, Linux kernel |
Working through binary search tree examples step by step is the only way to genuinely internalize these operations. Reading code isn’t enough — trace each one by hand on a small tree.
The recursive version is readable:
bool search(Node* root, int key) {
if (root == nullptr) return false;
if (root->data == key) return true;
if (key > root->data) return search(root->right, key);
return search(root->left, key);
}
The iterative version is safer for production — it uses O(1) space instead of O(h) call stack:
bool search(Node* root, int key) {
while (root != nullptr) {
if (root->data == key) return true;
root = (key > root->data) ? root->right : root->left;
}
return false;
}
Among all binary search tree examples, search is the one where iterative wins clearly in production environments. Stack overflow on deep unbalanced trees is a real failure mode.
Node* insert(Node* root, int key) {
if (root == nullptr) return new Node(key);
if (key < root->data)
root->left = insert(root->left, key);
else if (key > root->data)
root->right = insert(root->right, key);
return root;
}
Equal values are silently ignored here. Know your duplicate-handling convention before implementing deletion.
Binary search tree examples for deletion are where most learners struggle. Each case is genuinely different.
Leaf node: Remove it. Set the parent’s pointer to null.
One child: The deleted node’s child takes its place directly.
Two children: Find the inorder successor (smallest in right subtree), copy its value, delete the successor.
Node* minValueNode(Node* node) {
while (node->left != nullptr)
node = node->left;
return node;
}
Node* deleteNode(Node* root, int key) {
if (root == nullptr) return nullptr;
if (key < root->data)
root->left = deleteNode(root->left, key);
else if (key > root->data)
root->right = deleteNode(root->right, key);
else {
if (root->left == nullptr) {
Node* temp = root->right;
delete root;
return temp;
} else if (root->right == nullptr) {
Node* temp = root->left;
delete root;
return temp;
}
Node* successor = minValueNode(root->right);
root->data = successor->data;
root->right = deleteNode(root->right, successor->data);
}
return root;
}
<!– IMAGE: Insert deletion diagram showing all 3 cases. Alt text: “binary search tree examples deletion cases leaf one-child two-children diagram” –>
These binary search tree examples are ordered by difficulty. Each one builds on the previous. Work through them in sequence.
This is one of the most commonly misunderstood binary search tree examples. Checking only immediate parent-child relationships fails — a node can satisfy the local rule while violating the global BST property.
bool isValidBST(Node* root, long min = LONG_MIN, long max = LONG_MAX) {
if (!root) return true;
if (root->data <= min || root->data >= max) return false;
return isValidBST(root->left, min, root->data) &&
isValidBST(root->right, root->data, max);
}
Use long bounds to handle edge cases where node values equal INT_MIN or INT_MAX.
Middle element becomes root. Recurse on both halves. O(n) time, O(log n) stack space.
Node* sortedArrayToBST(vector<int>& arr, int start, int end) {
if (start > end) return nullptr;
int mid = start + (end - start) / 2;
Node* root = new Node(arr[mid]);
root->left = sortedArrayToBST(arr, start, mid - 1);
root->right = sortedArrayToBST(arr, mid + 1, end);
return root;
}
This binary search tree example appears in database bulk-loading, test fixture generation, and BST rebuilds after batch deletions.
Inorder traversal visits nodes in ascending order. Count as you go:
int kthSmallest(Node* root, int& count, int k) {
if (!root) return -1;
int left = kthSmallest(root->left, count, k);
if (left != -1) return left;
if (++count == k) return root->data;
return kthSmallest(root->right, count, k);
}
If this binary search tree example operation needs to run frequently on large trees, augment each node with a subtree size to bring k-th smallest from O(n) down to O(log n).
Replace every node’s value with the sum of all greater values. Reverse inorder (right → root → left) handles this in one pass:
void toGreaterSumTree(Node* root, int& sum) {
if (!root) return;
toGreaterSumTree(root->right, sum);
sum += root->data;
root->data = sum;
toGreaterSumTree(root->left, sum);
}
Watch for a common bug in this binary search tree example online: some versions compute root->data = sum - root->data instead of root->data = sum. Always trace through a small tree by hand before trusting any code.
Using a hash set for O(n) time, O(n) space:
bool findPair(Node* root, unordered_set<int>& seen, int target) {
if (!root) return false;
if (seen.count(target - root->data)) return true;
seen.insert(root->data);
return findPair(root->left, seen, target) ||
findPair(root->right, seen, target);
}
This binary search tree example has a space-efficient alternative: convert to a sorted array via inorder traversal, then apply two pointers. Same O(n) time, O(1) extra space if done in-place.
The clean path for this binary search tree example: inorder-traverse both trees into sorted arrays, merge them (merge sort style), then build a balanced BST from the result. Total: O(m + n) time, O(m + n) space.
For constrained memory: convert each BST to a doubly-linked list in-place, merge the lists, reconstruct. Uses O(h₁ + h₂) auxiliary space rather than O(m + n).
Two nodes were swapped by mistake. An inorder traversal finds violations — positions where a node’s value is smaller than the previous one:
Node *first = nullptr, *second = nullptr, *prev = nullptr;
void findSwapped(Node* root) {
if (!root) return;
findSwapped(root->left);
if (prev && root->data < prev->data) {
if (!first) first = prev;
second = root;
}
prev = root;
findSwapped(root->right);
}
After identifying first and second, swap their values. The tricky part of this binary search tree example: if the swapped nodes are adjacent in inorder sequence, there’s only one violation rather than two. The code handles this because first is set on the first violation and second keeps updating.
The count follows the nth Catalan number: C(2n, n) / (n+1). For n=10, that’s 16,796 distinct trees.
vector<Node*> generateTrees(int start, int end) {
if (start > end) return {nullptr};
vector<Node*> result;
for (int i = start; i <= end; i++) {
auto leftTrees = generateTrees(start, i - 1);
auto rightTrees = generateTrees(i + 1, end);
for (Node* left : leftTrees)
for (Node* right : rightTrees) {
Node* root = new Node(i);
root->left = left;
root->right = right;
result.push_back(root);
}
}
return result;
}
This binary search tree example has exponential time complexity — unavoidable when the output itself grows exponentially. Use memoization if you only need counts, not the actual trees.
For a complete reference on BST implementations across languages, see GeeksforGeeks BST reference.
Working through binary search tree examples in isolation is useful. Applying them correctly in real code is a different skill. Here’s what separates implementations that hold up from ones that break under real conditions.
Use iterative traversal in production code. Recursive binary search tree examples look clean, but deep trees overflow the call stack. An explicit heap stack is safer.
Augment nodes when you need extended performance. Adding a size field to each node enables O(log n) rank and select operations — common in leaderboards, percentile calculations, and order statistics. These binary search tree examples are worth knowing even if you don’t need them today.
Always test with sorted input first. Every binary search tree examples guide should say this louder. Sorted insertion is the worst case and the first thing any interviewer will try.
Reach for std::set or std::map in real projects. These Red-Black tree implementations are debugged at scale. Build your own only when you have specific requirements they can’t meet.
Match your self-balancing choice to your workload. AVL trees for read-heavy scenarios. Red-Black trees for write-heavy. B-Trees for disk or cache-sensitive applications. Most binary search tree examples tutorials skip this distinction — don’t let that be you.
LONG_MIN/LONG_MAX bounds when node values sit at integer extremes.Binary search tree examples degrade fast on sorted or nearly-sorted input. Every new value lands in a straight line and the height becomes n.
Solution A — Use a self-balancing variant. AVL trees keep height within 1.44 log₂(n). Red-Black trees within 2 log₂(n+1). Both maintain O(log n) for all core operations across any binary search tree examples you’ll encounter.
Solution B — Build from sorted data. If your BST is constructed once and rarely modified, build from a sorted array using the middle-element technique. Balanced result, no rotation logic needed.
Binary search tree examples in concurrent environments need locking. Tree-wide locks are safe but slow. Fine-grained per-node locks are faster but extremely difficult to implement correctly — especially during rotations.
Solution: Most production systems use single-writer/multiple-reader patterns or lock-free alternatives. Correct concurrent BST locking is harder than most binary search tree examples make it appear.
Each BST node is a separate heap allocation. On large trees, pointer-chasing causes cache misses that hurt performance beyond what raw operation count predicts. Binary search tree examples in textbooks rarely model this.
Solution: B-Trees store multiple keys per node, dramatically improving cache line utilization. For in-memory workloads where cache behavior matters, B-Tree variants or cache-oblivious BST layouts are worth considering.
💡 Next step: Once you’ve mastered these binary search tree examples, explore how AVL trees fix the balance problem automatically. Read our deep-dive: AVL Trees: Self-Balancing BSTs Explained.
Binary search tree examples always start here. A regular binary tree has no ordering constraint — values go anywhere as long as each node has at most two children. A BST adds the ordering rule: left subtree values are always smaller than the current node, right subtree values always larger. That single rule enables efficient search. Without it, finding a value means checking every node.
When you insert values in ascending order, each new value is larger than everything already in the tree. Every insertion lands at the rightmost position — the tree never branches left. Height becomes n instead of log n, and all operations degrade to O(n). Most binary search tree examples using sorted data are specifically demonstrating this worst-case scenario to motivate self-balancing trees.
Use a BST when you need ordered operations: range queries, minimum or maximum lookup, sorted iteration, or nearest-value search. Hash maps support none of these efficiently. Binary search tree examples involving range queries or sorted traversal are cases where a BST wins clearly over a hash map regardless of the constant factors.
Both guarantee O(log n) operations. AVL trees enforce stricter balance — height difference between left and right subtrees at any node is at most one. This makes lookups slightly faster. Red-Black trees allow more imbalance but require fewer rotations during insert and delete. Most binary search tree examples in production codebases use Red-Black trees (C++ std::map, Java TreeMap) because write performance tends to matter more than lookup speed.
The standard BST definition assumes unique keys. Common approaches: allow equal values in the right subtree, store a count per node (cleanest for most binary search tree examples), or store a list of records per node. Each approach changes how deletion works — decide before you implement.
The inorder successor is the next larger value in the tree — the smallest value in the right subtree. Binary search tree examples for deletion with two children use the inorder successor because you can’t remove a two-child node directly without disconnecting the tree. Copy the successor’s value into the current node, then delete the successor, which has at most one child. BST property is preserved throughout.
The seven that appear most frequently: BST validation, sorted array to balanced BST, k-th smallest element, lowest common ancestor, BST to sorted doubly-linked list, two swapped nodes fix, and two sum in BST. Working through these binary search tree examples covers the full range of traversal, structural, and transformation problems interviewers typically ask.
Binary search trees reward understanding over memorization. Once you genuinely grasp why the BST property enables O(log n) search, the operations stop feeling like rules to memorize and start feeling like logical consequences of a single organizing principle. Every one of the binary search tree examples in this guide follows from that one rule.
The eight binary search tree examples here were chosen to cover real interview problems and production patterns — from basic validation to structural transformation. Work through each one by hand on a small tree before trusting the code. Draw the diagrams. Trace the inorder traversals. That manual practice builds the intuition that no amount of passive reading can replace.
One practical note: for most production projects, reach for std::set, TreeMap, or your language’s equivalent before rolling your own BST. These are battle-tested Red-Black tree implementations. The value of studying binary search tree examples isn’t to write BSTs from scratch every day — it’s to understand the systems you’re building on top of, debug performance problems when they appear, and make informed architectural decisions.
Every binary search tree example you trace through makes the next one faster to understand. Eventually the structure stops feeling like a data structure and starts feeling like a natural way of thinking about ordered data. That’s the real goal — and you’re closer than you were an hour ago.
🔗 Continue learning: Big O Notation for Beginners · AVL Trees: Self-Balancing BSTs Explained