Category: Trees
Topics: balanced BST, ordered maps/sets, database indexing, consistent performance
A self-balancing binary search tree where the heights of the left and right subtrees of every node differ by at most one, guaranteeing O(log n) operations.
| Operation | Time | Description |
|---|---|---|
| Search | O(log n) | Guaranteed balanced height |
| Insert | O(log n) | Insert + rebalance |
| Delete | O(log n) | Delete + rebalance |
| Min/Max | O(log n) | Traverse to leaf |
class AVLNode:
def __init__(self, val):
self.val = val
self.left = None
self.right = None
self.height = 1
class AVLTree:
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 rotate_right(self, y):
"""Right rotation for Left-Left case"""
x = y.left
T2 = x.right
x.right = y
y.left = T2
self.update_height(y)
self.update_height(x)
return x
def rotate_left(self, x):
"""Left rotation for Right-Right case"""
y = x.right
T2 = y.left
y.left = x
x.right = T2
self.update_height(x)
self.update_height(y)
return y
def insert(self, root, val):
# Standard BST insert
if not root:
return AVLNode(val)
if val < root.val:
root.left = self.insert(root.left, val)
else:
root.right = self.insert(root.right, val)
# Update height
self.update_height(root)
# Get balance factor
balance = self.balance_factor(root)
# Left-Left case
if balance > 1 and val < root.left.val:
return self.rotate_right(root)
# Right-Right case
if balance < -1 and val > root.right.val:
return self.rotate_left(root)
# Left-Right case
if balance > 1 and val > root.left.val:
root.left = self.rotate_left(root.left)
return self.rotate_right(root)
# Right-Left case
if balance < -1 and val < root.right.val:
root.right = self.rotate_right(root.right)
return self.rotate_left(root)
return root
def search(self, root, val):
if not root or root.val == val:
return root
if val < root.val:
return self.search(root.left, val)
return self.search(root.right, val)
O(n) for n nodes. Each node stores additional height information (one integer). Recursive operations use O(log n) stack space.
Pros:
Cons: