Binary Search Tree

Trees
avg O(log n)

A binary search tree keeps values sorted inside a linked structure: everything smaller than a node lives in its left subtree, everything bigger in its right. That one rule turns every lookup into binary search - each comparison drops a whole subtree from consideration. But unlike a sorted array, a BST also accepts inserts and deletes without shifting anything. It is the idea underneath database indexes, sorted maps, and ordered sets - binary search as a living structure.

Watch the tree grow, then answer

Press play - or drag the timeline and step through it yourself.
Operation 1Comparisons 0Step 1 / 29

Start with an empty tree. Insert 8, 3, 10, 1, 6, 14, 4 one by one - smaller goes left, bigger goes right. Then search for 6 and for 7.

comparing in the tree just placed / found parent link

Complexity

Best
O(log n)
Input already in order
Average
O(log n)
Normal mixed input
Worst
O(n)
Worst possible input
Space
O(n)
Extra memory used

A park full of signposts

Imagine a park where every path splits in two, and every split has a signpost with a number on it. The park has one rule: everything smaller than the sign is down the left path, everything bigger is down the right. To find locker 6 you never wander - at sign 8 you go left, at sign 3 you go right, and there it is, three steps in a park of hundreds. Installing a new locker is just as easy: follow the signs until a path dead-ends, and build it right there. The signs stay honest, because the rules told you exactly where it belongs. That is a binary search tree - a structure where the data itself is the map.

How it works, step by step

  1. One rule, everywhere: keys smaller than a node live in its left subtree, bigger keys live in its right subtree.

  2. Search: start at the root. Equal? Found. Smaller? Go left. Bigger? Go right. Repeat until you hit the key or fall off the tree.

  3. Insert: run the same search. It always ends at an empty spot - and that empty spot is exactly where the new node belongs.

  4. Delete: a leaf just disappears; a node with one child is replaced by that child; a node with two children first swaps its key with its in-order successor.

  5. Every step drops a whole subtree, so a balanced tree answers in O(log n) comparisons - about 20 steps for a million keys.

  6. Bonus: an in-order walk (left, node, right) visits the keys in sorted order - free sorted output, any time.

The code, in JavaScript

The whole data structure is a key and two pointers. Insert is just a search that ends at a null pointer - the empty spot IS the answer. This version sends equal keys right; see the gotchas.

javascript
class Node {
  constructor(key) {
    this.key = key;
    this.left = null;    // everything smaller lives down here
    this.right = null;   // everything bigger lives down here
  }
}

function insert(root, key) {
  const node = new Node(key);
  if (root === null) return node;      // empty tree: new node is the root

  let cur = root;
  for (;;) {
    if (key < cur.key) {
      if (cur.left === null) { cur.left = node; break; }   // empty spot!
      cur = cur.left;
    } else {
      if (cur.right === null) { cur.right = node; break; } // (>= goes right)
      cur = cur.right;
    }
  }
  return root;             // the root never changes on a non-empty tree
}

let root = null;
for (const k of [8, 3, 10, 1, 6, 14, 4]) root = insert(root, k);
// Shape now:        8
//                 /   \
//                3     10
//               / \      \
//              1   6      14
//                 /
//                4

Dry run: insert 8, 3, 10, 1, 6, 14, 4 - then search for 6 and 7

The same steps the visualizer plays, written as a table. Generated by running the real algorithm - not written by hand.

StepOperationWhat happened
12Insert 3: 3 < 8 - go left.
23Insert 10: 10 > 8 - go right.
34Insert 1: 1 < 8 - go left.
441 < 3 - go left.
55Insert 6: 6 < 8 - go left.
656 > 3 - go right.
76Insert 14: 14 > 8 - go right.
8614 > 10 - go right.
97Insert 4: 4 < 8 - go left.
1074 > 3 - go right.
1174 < 6 - go left.
1286 < 8 - go left.
1386 > 3 - go right.
1486 equals 6 - found it! 3 comparisons, not a scan of all 7 values.
1597 < 8 - go left.
1697 > 3 - go right.
1797 > 6 - go right.

Good choice when…

  • You need lookups and inserts and deletes on ordered data - a sorted array searches fast but pays O(n) to insert.
  • You need order questions a hash map cannot answer: min, max, floor, ceiling, "all keys between a and b", k-th smallest.
  • You want sorted iteration at any moment - an in-order walk streams the keys in order, with no sort call.
  • You are building the mental model for real engines: database indexes (B-trees) and sorted maps in standard libraries (Red-Black trees) are this exact idea, hardened.

Bad choice when…

  • You only ever do exact-key lookups - a hash map is O(1) and simpler; the tree's O(log n) buys order you never use.
  • Your input arrives sorted (or nearly sorted) and your BST is plain - it degenerates into a linked list; reach for a self-balancing tree instead.
  • The data is known up front and never changes - sort it into an array once and binary search that; no pointers, better cache behavior.

Common mistakes

  • The O(log n) promise requires balance, and a plain BST does nothing to keep it. Insert 1, 2, 3, 4, 5 in that order and you have built a linked list - search, insert and delete all become O(n). That failure mode is exactly why AVL trees, Red-Black trees and B-trees exist: the same rule, plus rotations that force the height to stay logarithmic.
  • Equal keys need a policy: always right, always left, or a count field on the node. There is no default, and answering "it depends" without picking one fails interviews - while mixing policies in one tree silently loses data.
  • Delete-with-two-children must go through the in-order successor (or predecessor). Grabbing one of the two children and linking it up directly either drops the other subtree or hangs keys where the order rule no longer holds. Copy the successor's key up, then delete the successor - it has at most one child by construction.
  • Validating a BST needs min/max bounds passed down, not parent-child checks. The classic wrong validator compares each node only with its own children - and accepts a 6 hiding deep inside the right subtree of a 10, because every local pair looks fine. Carry (low, high) down and tighten one bound at every step.

Binary Search Tree vs. its closest relatives

AlgorithmBestAverageWorstSpaceStable
Binary Search Treethis pageO(log n)O(log n)O(n)O(n)-
Binary SearchO(1)O(log n)O(log n)O(1)-
Tree TraversalsO(n)O(n)O(n)O(h)-
Trie (Prefix Tree)O(m)O(m)O(m)O(n·m)-