Binary Search Trees (BST)

A Binary Search Tree (BST) is a binary tree with a special ordering property: for every node, all values in its left subtree are strictly smaller, and all values in its right subtree are strictly larger. This invariant applies recursively at every level—it must hold not just between a parent and its direct children, but throughout every subtree. When the tree is reasonably balanced, this structure enables search, insertion, and deletion in O(log n) time.

Consider a BST like a sorted phone book: to find a name, you open to the middle, decide whether your target comes before or after that page, and jump to the relevant half—skipping the other half entirely. Each comparison eliminates a large portion of the remaining candidates.

Rendering diagram...

The BST Property#

The BST invariant states that:

  • All nodes in the left subtree have values less than the current node
  • All nodes in the right subtree have values greater than the current node
  • Both subtrees must also be valid BSTs
Rendering diagram...
Rendering diagram...

In the invalid tree above, node 60 appears in the left subtree of 50. Even though 60 is locally valid relative to its direct parent 30 (since 60 > 30), it violates the BST property with respect to ancestor 50 (since 60 > 50). This illustrates a critical point: the BST invariant must hold globally against all ancestors, not just the immediate parent.

BST Node Structure

A BST node is the same as a binary tree node, but values must follow BST ordering

BST node class and demonstration that inorder gives sorted output

BST Operations#

Search Operation#

Searching in a BST works by comparing the target against the current node and descending into exactly one subtree—entirely ignoring the other. In a balanced BST, this eliminates roughly half of the remaining candidates at each step, producing O(log n) performance. If the tree is skewed, fewer nodes are eliminated per step, and in the worst case (a fully right- or left-leaning chain), search degrades to O(n).

Searching for 40
Rendering diagram...

BST Search

Find a value in a BST by comparing and navigating left or right

Time:O(log n)Space:O(h)Best:O(1)Worst:O(n)Avg:O(log n)

Insert Operation#

Inserting a new value involves searching for the correct position (the location where a search would fail) and attaching the new node there.

Before Insert 35
Rendering diagram...
After Insert 35
Rendering diagram...

BST Insert

Add a new value to the BST while maintaining the BST property

Time:O(log n)Space:O(h)Best:O(1)Worst:O(n)Avg:O(log n)

Delete Operation#

Deletion is the most complex BST operation because simply removing a node can break the tree's connectivity. The approach depends on how many children the node has, giving rise to three distinct cases:

Case 1: Leaf Node
Rendering diagram...
Case 2: One Child
Rendering diagram...
Case 3: Two Children
Rendering diagram...
CaseConditionSolution
Case 1Node is a leaf (no children)Simply remove the node
Case 2Node has one childReplace node with its child
Case 3Node has two childrenReplace with inorder successor (or predecessor)

Cases 1 and 2 are straightforward: remove the node and rewire the parent's pointer to the surviving child (or to null if there is none). Case 3 is the tricky one: when both children exist, you cannot simply remove the node without disconnecting two subtrees.

The standard solution is to find the node's inorder successor—the smallest value in its right subtree (the leftmost node there)—copy that value into the current node, then delete the successor from the right subtree. This works because:

  • The successor is larger than everything in the left subtree (it came from the right subtree).
  • The successor is the smallest node in the right subtree, so it is smaller than everything else that remains there.
  • The successor has at most one child (a right child), so deleting it reduces to Case 1 or Case 2.

BST Delete

Remove a value from BST while maintaining the BST property

Time:O(log n)Space:O(h)Best:O(1)Worst:O(n)Avg:O(log n)

Find Min and Max#

Finding the minimum and maximum values in a BST follows directly from the ordering property. Since every value smaller than a node lies in its left subtree, the overall minimum is always the leftmost node in the tree—you simply follow left child pointers until there are none. Symmetrically, the maximum is always the rightmost node. There is no need to scan the entire tree; you reach the answer in O(h) steps, where h is the tree's height.

Finding Min and Max
Rendering diagram...

Find Min and Max in BST

Find the smallest and largest values by traversing left or right

Time:O(h)Space:O(1)Best:O(1)Worst:O(n)

Inorder Successor and Predecessor#

The inorder successor of a node is the next node in sorted (inorder) order—the smallest value in the tree that is strictly greater than the target. The inorder predecessor is the previous node in sorted order—the largest value strictly less than the target.

Finding the successor depends on the node's position in the tree:

  • If the node has a right subtree: the successor is the leftmost (minimum) node in that subtree.
  • If the node has no right subtree: the successor is the nearest ancestor from which you last turned left—the lowest ancestor for which the target node lies in its left subtree. This case requires traversing upward, which in turn requires parent pointers.

The iterative algorithm below handles both cases using a single top-down pass from the root, keeping track of the last ancestor where we went left.

Finding Inorder Successor of 30
Rendering diagram...

Inorder Successor

Find the next larger value in a BST

Time:O(h)Space:O(1)

BST Validation#

A common task—and a classic interview question—is to verify whether a given binary tree is a valid BST. The challenge is that checking each node only against its direct children is not sufficient. A value can be locally correct relative to its parent while still violating the BST property relative to a higher ancestor (as the invalid tree diagram above demonstrates with node 60).

The correct approach propagates valid value ranges down the tree during recursion. Each node inherits a lower bound and an upper bound from its ancestors, and its value must fall strictly within those bounds. Any violation at any depth immediately disqualifies the tree.

Validate BST

Check if a binary tree satisfies the BST property

Validate BST by passing min/max bounds down the tree

Build BST from Sorted Array#

Given a sorted array, we can construct a height-balanced BST by recursively picking the middle element as the root at each level. This works because placing the median at the root splits the remaining elements as evenly as possible between the left and right subtrees, minimizing the overall height. A balanced BST of n nodes has height O(log n), which is what keeps all operations efficient. Inserting from the front instead would produce a right-skewed chain of height n.

Building BST from [10, 20, 30, 40, 50, 60, 70]
Rendering diagram...
Resulting Balanced BST
Rendering diagram...

Build Balanced BST from Sorted Array

Create a height-balanced BST by recursively picking middle elements

Time:O(n)Space:O(log n)Best:O(n)Worst:O(n)

Complexity Analysis#

BST operation complexities depend heavily on tree balance

OperationAverage CaseWorst CaseNotes
SearchO(log n)O(n)Worst when tree is skewed
InsertO(log n)O(n)Worst when inserting sorted data
DeleteO(log n)O(n)Finding successor adds O(h)
Find Min/MaxO(log n)O(n)O(h) where h is height
Inorder SuccessorO(log n)O(n)Depends on tree balance
Space (tree)O(n)O(n)n nodes stored

When BST Performance Degrades#

Inserting data in sorted (or reverse-sorted) order into a plain BST causes it to degenerate into a linked list. Every new node is always appended at the rightmost (or leftmost) position, and the resulting tree has height n instead of log n. Operations that should take O(log n) on a balanced tree now take O(n)—a dramatic difference for large datasets.

Balanced: Insert 50,30,70,20,40
Rendering diagram...
Skewed: Insert 10,20,30,40,50
Rendering diagram...

When BST Degrades to O(n)

Understanding worst-case scenarios for BST operations

Demonstrating how sorted insertion creates worst-case BST

Applications of BST#

ApplicationWhy BST?
Dictionary/MapO(log n) search, insert, delete with ordered keys
Database IndexesFast range queries with inorder traversal
Priority QueueO(log n) insert and delete-min, though heaps are typically preferred for simpler implementation and better cache locality
Set ImplementationUnique elements with O(log n) membership test
Auto-completeFind all words with given prefix using range query
Symbol TablesCompiler symbol lookup with scope ordering
SchedulingEvent scheduling with time-ordered access

Reviewing AI-Generated Code#

BST code is deceptively tricky: the invariant must hold globally across the entire tree, not just locally at each node. AI-generated BST code often looks correct at a glance but contains subtle bugs in validation logic (checking only the direct parent instead of all ancestors) and deletion logic (copying the successor's value without then removing the successor node). Knowing these failure patterns lets you spot errors quickly.

IssueWhat to CheckCommon AI Mistake
BST validationCheck against ALL ancestors, not just parentOnly comparing with direct parent
Deletion casesHandle all 3 cases correctlyForgetting the two-children case
Successor logicFind minimum in right subtreeConfusing successor with predecessor
Pointer updatesUpdate both child and parent pointersBreaking tree structure
Duplicate handlingDecide on a consistent policyInconsistent duplicate treatment

Spotting AI BST Bugs

Common errors in AI-generated BST code

Correct BST validation checking against ALL ancestors

Questions to Ask When Reviewing BST Code#

  1. "Does this validate against all ancestors?" — BST validation must propagate min/max bounds down the tree, not just compare a node against its immediate parent.
  2. "What does the tree look like after deleting a node with two children?" — Confirm that the successor's value is copied into the deleted node and that the successor is then removed from the right subtree.
  3. "What happens if I insert already-sorted values?" — The tree should degrade to a linked list. If the code behaves differently, verify whether a hidden balancing mechanism is present.
  4. "How does it handle duplicates?" — There should be a clear, consistently applied policy: ignore them, place them left, or place them right.

Summary#

ConceptKey Point
BST PropertyLeft subtree < Node < Right subtree (recursively)
SearchO(log n) average by comparing and going left/right
InsertSearch for position, attach new node as leaf
Delete3 cases: leaf, one child (bypass), two children (successor)
Min/MaxLeftmost/rightmost node in O(h) time
SuccessorNext larger value; smallest in right subtree or ancestor
ValidationPass min/max bounds recursively, not just parent
Balance MattersBalanced: O(log n), Skewed: O(n) - use AVL/Red-Black

BSTs provide O(log n) average performance when the tree remains reasonably balanced, but degrade to O(n) when insertion patterns produce a skewed tree—such as inserting already-sorted data. For workloads where input order is unpredictable, a plain BST is often sufficient. When O(log n) must be guaranteed regardless of input, self-balancing trees are required. Continue to AVL Trees to see how rotations automatically restore balance after every insertion and deletion.