Menu
Coddy logo textTech

AVL Tree

Last updated

An AVL tree is a self-balancing binary search tree. It works like a normal BST, but after every insertion it checks each ancestor's balance factor - the height difference between its left and right subtrees - and if any node becomes unbalanced (a difference greater than 1), it performs rotations to restore balance. Press play above to watch values inserted and the tree rotate itself back into shape.

Because it never lets the tree get more than slightly lopsided, an AVL tree guarantees O(log n) height, so search, insert, and delete are always O(log n) - even for sorted input that would wreck a plain BST. The cost is the extra rotations and height bookkeeping on each insert.

Time & space complexity

OperationComplexityNotes
SearchO(log n)Height is always ~1.44 log n
InsertO(log n)Plus O(1) rotations
DeleteO(log n)Plus O(log n) rotations
SpaceO(n)One height field per node

The four rotation cases

CaseImbalanceFix
Left-LeftHeavy on left child's leftOne right rotation
Right-RightHeavy on right child's rightOne left rotation
Left-RightHeavy on left child's rightLeft, then right rotation
Right-LeftHeavy on right child's leftRight, then left rotation

Worked example

Inserting [10, 20, 30, 40, 50, 25] one value at a time:

StepStructureAction
Insert 1010First node becomes the root; balanced
Insert 2010(_, 20)Goes right of 10; still balanced
Insert 3020(10, 30)Right-Right at 10, so one left rotation lifts 20 to the root
Insert 4020(10, 30(_, 40))Goes right of 30; every balance factor stays within ±1
Insert 5020(10, 40(30, 50))Right-Right at 30, so a left rotation at 30 lifts 40
Insert 2530(20(10, 25), 40(_, 50))Right-Left at 20: right-rotate 40's subtree, then left-rotate 20

When to use an AVL tree

Use it whenAvoid it when
Lookups vastly outnumber inserts and you want the tightest possible heightInserts and deletes dominate - the extra rotations and rebalancing cost more than a red-black tree's
You need guaranteed O(log n) worst case, even for adversarial or sorted inputA plain hash table would do - you don't need ordered traversal or range queries
You need ordered operations: in-order traversal, predecessor/successor, range queriesThe data set is tiny - a plain BST or sorted array is simpler and fast enough
Data may arrive already sorted, which would turn an unbalanced BST into a linked listYou can't afford the per-node height field's extra memory in a very tight footprint

AVL Tree code

A clean, runnable AVL Tree implementation in Python, JavaScript, Java, C++, C. Pick a language, copy the code, or open it pre-loaded in the Coddy Playground.

AVL Tree code in Python

Python
1class Node:2    def __init__(self, key):3        self.key = key4        self.left = None5        self.right = None6        self.height = 17
8
9def height(node):10    return node.height if node else 011
12
13def update(node):14    node.height = 1 + max(height(node.left), height(node.right))15
16
17def rotate_right(y):18    x = y.left19    y.left = x.right20    x.right = y21    update(y)22    update(x)23    return x24
25
26def rotate_left(x):27    y = x.right28    x.right = y.left29    y.left = x30    update(x)31    update(y)32    return y33
34
35def insert(node, key):36    if node is None:37        return Node(key)38    if key < node.key:39        node.left = insert(node.left, key)40    else:41        node.right = insert(node.right, key)42    update(node)43    balance = height(node.left) - height(node.right)44    # Four imbalance cases: LL, RR, LR, RL45    if balance > 1 and key < node.left.key:46        return rotate_right(node)47    if balance < -1 and key > node.right.key:48        return rotate_left(node)49    if balance > 1:50        node.left = rotate_left(node.left)51        return rotate_right(node)52    if balance < -1:53        node.right = rotate_right(node.right)54        return rotate_left(node)55    return node56
57
58def inorder(node):59    if node is None:60        return []61    return inorder(node.left) + [node.key] + inorder(node.right)62
63
64root = None65for key in [10, 20, 30, 40, 50, 25]:66    root = insert(root, key)67
68print("Inorder:", inorder(root))69print("Root:", root.key, "| tree height:", root.height)
Run this code in the Python Playground

AVL Tree FAQ

What is a balance factor in an AVL tree?
The balance factor of a node is the height of its left subtree minus the height of its right subtree. An AVL tree keeps every node's balance factor at -1, 0, or +1; if an insertion pushes it outside that range, a rotation restores balance.
What is the difference between an AVL tree and a red-black tree?
Both are self-balancing BSTs with O(log n) operations. AVL trees are more strictly balanced, so lookups are slightly faster, but they may do more rotations on insert/delete. Red-black trees are more loosely balanced, favoring fewer rotations - which is why many standard libraries use them for maps and sets.
Why use an AVL tree over a plain binary search tree?
A plain BST can degrade to O(n) operations if values arrive in sorted order, forming a skewed chain. An AVL tree rotates to stay balanced, guaranteeing O(log n) height and operations regardless of insertion order.
Is an AVL tree better than a red-black tree for a database index?
It depends on the workload. AVL trees are more rigidly balanced, so they win when reads dominate and you want the shortest possible search paths. But most databases and language libraries choose red-black trees (or B-trees) because they rebalance with fewer rotations on write-heavy workloads, which matters more when inserts and deletes are frequent.
How many rotations does a single AVL insertion need?
At most one rotation - either a single or a double (two-step) rotation - is ever needed to rebalance the tree after inserting one value. That is because an insertion increases a subtree's height by at most one, so a single fix at the lowest unbalanced ancestor is enough. Deletion is different: it can require up to O(log n) rotations as the rebalancing propagates toward the root.
Do I need to update node heights after every rotation?
Yes - a common bug is rotating pointers correctly but forgetting to recompute the height of the two nodes involved. After each rotation you must update the height of the demoted node first, then the promoted node, because the promoted node's height depends on its new children. Skipping this leaves stale balance factors that break future rebalancing decisions.
Coddy programming languages illustration

Master algorithms with Coddy

GET STARTED