Quiz 2

17. AVL Trees — Self-Balancing BSTs

635 words
3 min read
Python Week 1: the first filter for runtime behavior
Visual companion
Python
Type and operator map

Python Week 1: the first filter for runtime behavior

View
Revision summary

What this note is really saying

Short form

# 17. AVL Trees — Self-Balancing BSTs > **What problem does this solve?** A BST can degenerate to O(n) height if inserted in sorted order.

17. AVL Trees — Self-Balancing BSTs

What problem does this solve? A BST can degenerate to O(n) height if inserted in sorted order. AVL trees maintain balance by automatically rotating nodes after every insert/delete, guaranteeing O(log n) height.

1. Balance Factor

Balance Factor = height(left subtree) − height(right subtree) An AVL tree requires |balance factor| ≤ 1 for every node. (Diagram)

2. AVL Rotations

When a node becomes unbalanced (bf = ±2), we perform one of four rotations:
ImbalanceTypeRotation
Left-Left (LL)Insert into left subtree of left childRight rotate
Right-Right (RR)Insert into right subtree of right childLeft rotate
Left-Right (LR)Insert into right subtree of left childLeft then Right
Right-Left (RL)Insert into left subtree of right childRight then Left
(Diagram)

3. Implementation

python
# runnable
class AVLNode:
    def __init__(self, val):
        self.val = val
        self.left = None
        self.right = None
        self.height = 1
class AVLTree:
    def __init__(self):
        self.root = None
    def height(self, node):
        return node.height if node else 0
    def balance_factor(self, node):
        return self.height(node.left) - self.height(node.right) if node else 0
    def update_height(self, node):
        node.height = 1 + max(self.height(node.left), self.height(node.right))
    def right_rotate(self, z):
        """Right rotate (fixes LL imbalance)."""
        y = z.left
        T2 = y.right
        y.right = z
        z.left = T2
        self.update_height(z)
        self.update_height(y)
        return y
    def left_rotate(self, z):
        """Left rotate (fixes RR imbalance)."""
        y = z.right
        T2 = y.left
        y.left = z
        z.right = T2
        self.update_height(z)
        self.update_height(y)
        return y
    def insert(self, val):
        """Insert val into AVL tree. O(log n)."""
        self.root = self._insert(self.root, val)
    def _insert(self, node, val):
        if node is None:
            return AVLNode(val)
        # Standard BST insert
        if val < node.val:
            node.left = self._insert(node.left, val)
        elif val > node.val:
            node.right = self._insert(node.right, val)
        else:
            return node  # No duplicates
        # Update height
        self.update_height(node)
        # Check balance and rotate
        bf = self.balance_factor(node)
        # LL case
        if bf > 1 and val < node.left.val:
            return self.right_rotate(node)
        # RR case
        if bf < -1 and val > node.right.val:
            return self.left_rotate(node)
        # LR case
        if bf > 1 and val > node.left.val:
            node.left = self.left_rotate(node.left)
            return self.right_rotate(node)
        # RL case
        if bf < -1 and val < node.right.val:
            node.right = self.right_rotate(node.right)
            return self.left_rotate(node)
        return node
    def inorder(self):
        result = []
        def _t(n):
            if n:
                _t(n.left)
                result.append(n.val)
                _t(n.right)
        _t(self.root)
        return result
# Test
avl = AVLTree()
for v in [10, 20, 30, 40, 50, 25]:
    avl.insert(v)
print(f"Inorder: {avl.inorder()}")
# Trace insert 10, 20, 30:
# Insert 10: root = 10
# Insert 20: 10.right = 20, bf(10) = -1 OK
# Insert 30: 10.right = 20, 20.right = 30
#   bf(10) = 0 - 2 = -2 (RR), bf(20) = -1
#   Left rotate at 10 → 20 becomes root
print("AVL tree is balanced after every insert!")

4. Complexity

PropertyValue
Height≈ 1.44 log₂(n) — guaranteed
Minimum nodes for height hS(h) = S(h−2) + S(h−1) + 1
SearchO(log n)
InsertO(log n)
DeleteO(log n)

Practice Questions

Q1. Insert [36, 40, 32, 18, 72, 5, 35, 34] into an AVL tree. Which nodes are leaves? Q2. What's the difference between an LL imbalance and an LR imbalance? Q3. Why can't we use simple BST rotations for self-balancing in all cases? Q4. How many nodes minimum in an AVL tree of height 5?
Answers
A1. After all insertions and rotations, leaf nodes are: 5, 35, 72. (Note: 32 gets rebalanced and becomes a leaf after rotations.)
A2. LL: insertion in left-left grandchild → single right rotate. LR: insertion in left-right grandchild → double rotate (left then right).
A3. BST rotations only fix local imbalance temporarily. AVL rotations use balance factors to detect and fix imbalances at the point of insertion, propagating upward.
A4. S(5) = S(4) + S(3) + 1. S(0)=1, S(1)=2, S(2)=4, S(3)=7, S(4)=12, S(5)=20. Join Discord Previous16. Binary Search TreesNext18. Heaps & Priority Queues
Document outline

Keep your place and jump directly to a heading.

Table of Contents
System Normal // Awaiting Context

Intelligence Hub

Navigate the knowledge graph to generate context. The Hub adapts dynamically to surface backlinks, related notes, and metadata insights.