Balanced Trees: AVL Trees and Insertion, Study notes of Data Structures and Algorithms

The concept of balanced trees, specifically avl trees. Avl trees are a self-balancing binary search tree where the height differences between the left and right subtrees of each node are kept minimal. The properties of avl trees, the insertion process, and the cases where rotations are required to maintain balance. It also mentions the advantages and disadvantages of avl trees compared to other self-balancing tree structures like splay trees.

Typology: Study notes

Pre 2010

Uploaded on 02/13/2009

koofers-user-ruh
koofers-user-ruh 🇺🇸

10 documents

1 / 17

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
Balanced Trees
CMSC 420: Lecture 7
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff

Partial preview of the text

Download Balanced Trees: AVL Trees and Insertion and more Study notes Data Structures and Algorithms in PDF only on Docsity!

Balanced Trees

CMSC 420: Lecture 7

Balance

left height(u) =

0 if LEFT(u) = NULL

1 + height(LEFT(u)) otherwise

u height (LEFT(u)) left_height (u) right_height defined analogously balance (u) := right_height (u) - left_height (u) Positive when right subtree is taller than left subtree 0 when the trees are the same height Negative when left subtree is taller than right subtree

Examples

0 +

- balance (u) := right_height (u) - left_height (u) 0 0 0 0 0 0 (^0 ) 0 +1 (^0 ) **-

-2** (^0) - NOT an AVL tree

Properties & Notes

  • All leaves have balance = 0
  • AVL tree with^ n^ nodes has height O(log^ n ). ⇒ (^) find will run in O(log n ) time if AVL has binary search tree property.
  • insert ,^ delete^ can be implemented in O(log^ n ) time. ⇒ Good structure to implement dictionary or sorted set ADTs.

u

AVL Insert

  • First, do a standard BST insert: do a find and add node where you “fall off the tree.”
  • Walk insertion path back up to root, updating balances.
  • If node was added to the left subtree, decrement balance by 1, otherwise increment balance by 1. Stop when node’s height doesn’t change.
  • If a balance becomes +2 or -2, fix it. m n s t x **0 0

0

0 0 -**

u

The Easy Cases

n h h- -10 u n h h 0+ Node was added to the shorter subtree Subtrees were equal, now slightly unbalanced The symmetric cases (when left subtree was shorter, e.g.) are handled the same way.

Left, Left Case

u n h i

- h h Too tall! Too short! u n h i h h Right rotation (aka clockwise rotation) 0 0 - Why does obey BST ordering?

Symmetric Left Rotation:

n i n i Left rotation (aka counterclockwise rotation) Only a constant # of pointers need to be updated for a rotation: O(1) time

The Critical Node

  • Rotations leave subtree rooted at critical node balanced with unchanged height. The critical node is the node on the insertion path closest to the leaves with balance ≠ 0 **0 0

0 -** critical node

Rotations preserve height of critical subtree

n h i h h 0 0 n h i

- h (^) h - height = h + height = h + n h+ i - k h h - h+ + n h+ i k h h h+ 0 + height = h +3 height = h +3 0 Left, Left Case: Left, Right Case:

AVL Trees

  • Nice Features:

     Worst case O(log _n_ ) performance guarantee 
    • Fairly simple to implement
  • Problem though:

     Have to maintain extra balance factor storage at each node. 
  • Splay trees (Sleator & Tarjan, 1985)

     remove extra storage requirement, 
    • even simpler to implement,
    • heuristically move frequently accessed items up in tree
    • amortized O(log n ) performance
    • worst case single operation is Ω( n )

Splay Trees

  • find (T, k):^ splay (T, k). If^ root (T) =^ k , return^ k , otherwise return not found.
  • insert (T, k):^ splay (T, k). If^ root (T) =^ k , return^ duplicate! ; otherwise, make k the root and add children as in figure.
  • concat (T 1 , T 2 ): Assumes all keys in T 1 are < all keys in T 2. Splay (T 1 , ∞). Now root T 1 contains the largest item, and has no right child. Make T 2 right child of T 1.
  • delete (T,^ k ):^ splay (T,^ k ). If root^ r^ contains^ k ,^ concat (LEFT( r ), RIGHT( r )).
splay (T, k ): if k ∈ T, then move k to the root. Otherwise, move
either the inorder successor or predecessor of k to the root.

Without knowing how splay is implemented, we can implement our usual operations as follows: j j k