AVL Trees AVL

Height of an AVL Tree • AVL trees are 4 balanced. 44 Insertion and restructuring 2 3 Removal and restructuring •An AVL Tree is a 17 78 binary 1 2 1 Costs 88 such that for every 32 50 1 1 internal v of T, 48 62 the heights of the children of v can

AVL tree, named after the initials of its differ by at most 1 An example of an AVL tree inventors: Adel’son-Vel’skii and Landis where the heights are shown 1 next to the nodes: 2 .

Balancing Factor Height of an AVL Tree = height(right s.a.) – height(left s.a.) • Proposition: The height of an AVL tree T storing n keys is ∈{-1, 0, 1} for AVL tree O(log n). + 1

0 –1 • Justification: The easiest way to approach this problem is to find n(h): the minimum number of internal nodes of an AVL tree of height h. 0 0 –1 0 • We see that n(1) = 1 and n(2) = 2 0 1

2

3 4

1 n(h): the minimum number of internal nodes of Height of an AVL Tree an AVL tree of height h.

For n ≥ 3, an AVL tree of height n(h) = 1 + n(h-1) + n(h-2) h contains the root node, one AVL subtree of height h-1 and the other AVL subtree of height h-2. h-2 h h-1 h-2 h-1 But: n(h-1) > n(h-2),

that is: n(h) > 1+ n(h-2) +n(h-2) i.e. n(h) = 1 + n(h-1) + n(h-2) which is > 2n(h-2)

so n(h) > 2n(h-2) 5 6

Height of an AVL Tree n(h) > 2in(h-2i) with n(1) = 1 So, now we know: n(h) > 2n(h-2) n(h) > 2n(h-4)= 2 2n(h-4) n(2) = 2 but then also: n(h-2) > 2n(h-4) h-2i = 1

n(h) > 4n(h-4) for i = h/2 - 1

but then also: n(h-4) > 2n(h-6) n(h) > 2h/2 - 1 n(1)

n(h) > 8n(h-4) h/2 - 1 We can continue: n(h) > 2 h/2 - 1 n(h) > 2n(h-2) log n(h) > log 2 n(h) > 4n(h-4) log n(h) > h/2 - 1 … h < 2 log n(h) + 2 i n(h) > 2 n(h-2i) 7 which means that h is O(log n) 8

2 Insertion Insertion Before After left After right insertion insertion • A T is called balanced if for every A 0 A –1 A + 1 node v, the height of v’s children differ by at most one.

• Inserting a node into an AVL tree involves performing an expandExternal(w) on T, which changes the heights A + 1 A 0 A + 2 of some of the nodes in T.

• If an insertion causes T to become unbalanced we have to rebalance... re-balancing A –1 A –2 A 0

9 10 re-balancing

Rebalancing

Rebalancing after insertion Step 1: Trace the back from the point of insertion to the first node whose grandparent is unbalanced. Label this node x, its parent y, and grandparent z. We are going to identify 3 nodes which form a grandparent, parent, child triplet and the 4 Examples ….. subtrees attached to them. We will rearrange z z these elements to create a new balanced tree. y y x x

11 12

3 Rebalancing Rebalancing

Step 3: Rename x, y, z to a, b, according to their Step 2: These nodes will have 4 subtrees connected inorder traversal i.e. if y< x < z then label y ‘a’, x to them. Label them T , T , T , T from left to right. 1 2 3 4 ‘b’ and z ‘c’. Examples ….. Example

z z y c = z y x a=y x T 4 T4 b= x T1 T3 T1 T2 T3 T2

13 14

Rebalancing Example

44 c Step 4: Replace the tree rooted at z with the z 6 17 a 78 7 following tree: 2 y 32 1 50 4 88 x b 48 62 b 3 5 54 T 3

T T 2 a c 0 T 1

44 b 4 x 17 62 a 2 y z 6 c T1 T2 T3 T4 32 50 78 1 3 5 7 48 54 88 Rebalance done! T2 T0 T1 T3 15 16

4 Example 1 Does this really work?

a We need to see that the new tree is : z y b a) A Binary search tree - the inorder traversal y z x of our new tree should be the same as that of h the old tree x c T h h+2 1 h h h-1 h b) Balanced: have we fixed the problem? T2 h-1 h T1 T2 T3 T4 T 3 T4 We consider 2 types of examples Inorder: T1 z T2 y T3 x T4 17 18

Example 2 An Observation…

x z c Notice that in both cases, the new tree rooted at y a y z b has the same height as the old tree rooted at z had before insertion. b h x h+2 h h-1 h h So.. once we have done one rebalancing act, we are T4 h done. T1 T2 T3 T4 h-1 h T1

T2 T3 Inorder: T1 y T2 x T3 z T4 19 20

5 rebalance (v) T1 <- a.left; T4 <- c.right x <- v; Y <- x.parent; z <- y.parent b.left <- a; b.right <- c while (z.isBalanced and not(z.isRoot) ) a.left <- T1; a.right <- T2 x <- y; y <- z; z <- z.parent c.left <- T3; c.right <- T4 Removal if ( not z.isBalanced) T1.parent <- a; T2.parent <-a if ( x = y.left) { x<=y} T3.parent <- b; T3.parent <- c • We can easily see that performing a if (y = z.left) {x<=y<=z} removeAboveExternal(w) can cause T to become a <- x; b <- y; c<- z; if (z.isRoot) then unbalanced. T2 <- x.right; T3 <- y.right; root <- b else { z<=x<=y} b.parent <- NULL •Let z be the first unbalanced node encountered while a <- z; b <- x; c <- y; else if (z.isLeftChild) travelling up the tree from w. Also, let y be the child of T2 <- x.left; T3 <- x.right; z.parent.left<-b z with the larger height, and let x be the child of y else {y<=x} else z.parent.right <- b if (y = z.left) {y<=x<=z} b.parent <- z.parent with the larger height. a <- y; b <- x; c <- z; a.parent <- b; c.parent <- b T2 <- x.left; T3 <- x.right • We can perform operation restructure(x) to restore else { z<=y<=x} balance at the subtree rooted at z. a <- z; b <- y; c <- x; • As this restructuring may upset the balance of another T2 <- y.left; T3 <- x.left node higher in the tree, we must continue checking for balance until the root of T is reached

21 22

Removal (contd.) Removal (contd.) the choice of x is not unique !!! • we could choose a different x: az z 4 Oh no, unbalanced! 44 a 4 y 44 1 3 y b 17 62 c 1 3 x 17 62 2 b 2 x c 50 78 Oh no, 2 2 1 1 0 1 50 78 T 0 48 54 88 unbalanced! 1 1 0 1 T0 48 54 88 32

T 2 T 1 T T 3 32 2

T 1 T 3 y 4 b 62 4 x z 50 3 x 2 44 78 z a yc 2 3 Whew, 2 44 62 1 0 Whew, 1 1 1 1 17 50 2 88 17 balanced! 1 1 balanced! 48 54 78 0 1 54 48 T 2 88 23 24 T 0 T 0 T T 3 1 T 2

6 COMPLEXITY

Searching: findElement(k): Inserting: insertItem(k, o): Removing: removeElement(k):

O(log n)

25

7