Balanced trees

A search tree is only fast while it stays bushy. Balanced trees repair themselves after every insert and delete with small rotations, so every operation stays O(log n) whatever order the data arrives in.

3 examples15 to practiceRead · 6 min
The problem

A search tree is only fast while it stays bushy

Binary trees & BSTs showed that search, insert and delete each cost one step per level, and that inserting values in sorted order builds a chain as tall as the number of values. A balanced tree repairs itself after every change so that its height stays O(log n), whatever the order of the changes.

The usual measure is the balance factor of a node: the height of its left subtree minus the height of its right subtree, where an empty subtree has height 0. A tree is height-balanced when every node's balance factor is −1, 0 or 1.

Basic

Balance is checked bottom up, from heights

A node's height needs both its children's heights first, so the check runs in postorder: each call returns its subtree's height, or −1 as soon as something below is unbalanced. The tree in the walkthrough is what a plain search tree looks like after inserting 5, 3, 8, 2, 4 and then 1.

Every node from 3 down is fine. Only the root is off: its left side is three levels deep and its right side one.

Rotations

A rotation lifts a child above its parent and keeps the order

The repair is a tree rotation. A right rotation at node 30 with left child 20 makes 20 the top of that subtree and 30 its right child. Whatever hung on 20's right, values between 20 and 30, moves across to become 30's left subtree. A left rotation is the mirror image.

302010201030leftleftrotate right at 30leftright302010201030leftleftrotate right at 30leftright

Before: a chain 30, 20, 10, three levels. After a right rotation at 30: 20 on top, two levels. Read left to right, both are 10, 20, 30.

The rule

A rotation changes three links and keeps every value in the same left-to-right order, so the tree is still a search tree. It costs O(1), and it moves one side up a level and the other down a level.

Medium

An AVL tree rotates on the way back up from an insert

An AVL tree is a binary search tree that stays height-balanced. Each node remembers its height. After an ordinary insert, the recursion returns up the path it came down; at each node it updates the height and computes the balance factor. The first node found at +2 or −2 is repaired with a rotation, and that one repair always restores the balance of everything above it.

When the new value went down the same side twice (left of the left child, or right of the right child), one rotation fixes it. The walkthrough inserts values that only ever cause that straight-line case. Real AVL nodes store their height in a field; here the heights live in a map from value to height, because the pseudocode's tree nodes have only a value and two children.

Hard

A zigzag needs two rotations

If the new value went left, then right (or right, then left), a single rotation at the unbalanced node just moves the bend to the other side. The fix is two rotations: first rotate the child the other way, which turns the zigzag into a straight line, then rotate at the unbalanced node as before. This is the double rotation, and it completes the four cases of the AVL insert.

Deleting works the same way, except that more than one node on the way up may need a repair: O(log n) rotations at most, each O(1).

In practice

Libraries give you a balanced tree as an ordered map

A red-black tree is the other common design. Every node is colored red or black, no red node has a red child, and every path from a node down to an empty spot passes the same number of black nodes. That bounds the height at 2 log₂(n + 1), looser than an AVL tree's roughly 1.44 log₂ n, but an insert or delete needs at most a few rotations, so updates are cheaper. Java's TreeMap and TreeSet are documented as red-black trees, and C++ standard libraries use them for std::map and std::set.

Need

Use

Keys in sorted order, with inserts and deletes

An ordered map or set: TreeMap, std::map

The smallest key at least x, or the largest at most x

ceilingKey / floorKey in Java, lower_bound in C++

Only the smallest or largest item, repeatedly

A heap is simpler and faster

Lookups by exact key only

A hash table

Python has no balanced tree in its standard library; the third-party sortedcontainers package is the usual stand-in. You will rarely write an AVL or red-black tree by hand. You will often need to recognize that a problem wants an ordered map: sorted keys that change as you go.

Check yourself

4 questions

1. What is a node's balance factor?
2. What does a rotation never change?
3. A new value went into the left child's right subtree, and the node above is now at +2. What fixes it?
4. Why do libraries often choose red-black trees over AVL trees?
Takeaways

Remember this

  • A balanced search tree repairs itself after each change, keeping its height O(log n) whatever the insert order.
  • The balance factor is left height minus right height; height-balanced means it is −1, 0 or 1 at every node.
  • A rotation lifts a child above its parent in O(1) and keeps the sorted left-to-right order.
  • An AVL insert rotates once for a straight-line imbalance and twice for a zigzag, at the first unbalanced node on the way up.
  • In practice, use the library's ordered map (often a red-black tree) whenever you need sorted keys that change.
Practice

Now solve some yourself

Only this topic 0 of 9 solved

  1. Easy
    Build a bushy search tree from a sorted list
    Balanced trees
  2. Medium
    Book a calendar with no double bookings
    Balanced trees
  3. Medium
    Sell each customer the dearest ticket within budget
    Balanced trees
  4. Medium
    Book a calendar with no triple bookings
    Balanced trees
  5. Medium
    Seat each student as far from others as possible
    Balanced trees
  6. Medium
    Track prices that arrive late and get corrected
    Balanced trees
  7. Medium
    The closest pair at least x positions apart
    Balanced trees
  8. Hard
    Longest unlit stretch after each new light
    Balanced trees
  9. Hard
    Remove every kth child in a circle, with many children
    Balanced trees

Mixed with topics you have practiced 0 unlocked

    6 more once you have practiced Tree traversals, Linked lists, Hash tables & maps, Greedy algorithms, Sliding window, Merge intervals. Play one of its examples to the end and solve one of its problems to unlock them.

    Problems open on their own sites (LeetCode, Codeforces, CodeChef, AtCoder, CSES) in a new tab. Tick Solved when you get it accepted there; your ticks decide which mixed problems open next.

    Next

    Lowest common ancestor

    Continue