BRONX COMMUNITY COLLEGE of the City University of New York DEPARTMENT OF MATHEMATICS AND COMPUTER SCIENCE CSI Section E01 AVL Trees AVL Property While BST structures have average performance of Θ(log(n)) for insert, find and delete, the worst-case performance occurs when a tree is created by adding new items in increasing (or decreasing) order. In this case, a binary search tree looks like a linked list, with all the links going the same way. In this case, the performance of the important methods (find, insert, delete) is Θ(n): 1 Variations of Binary Search Trees, such as red-black trees and splay trees, have been designed to rebalance themselves whenever the subtrees of any node become too unbalanced, as in the above example. One of these variations, AVL trees, have a balance property which gives them Θ(log(n)) performance for insert, find and delete, even in the worst-case order that item values are inserted. This is guaranteed by the AVL Property which says that, for any node in an AVL tree, its left and right subtrees will have heights which differ by at most one level. AVL trees obtain this property by performing rotation operations whenever a violation of the AVL property is detected after a normal insertion or deletion operation. Such rebalancing operations restore the AVL property, and guarantee Θ(log(n)) performance. The way these operations are implemented, while still enforcing the BST property, are discussed below. Aside from 1
these private methods used after the usual BST operations, the AVL Class interface is the same as for the BST Class. AVLTree Class AVLTree Balanced Binary Search Tree. For any node, the height of its left subtree and the height of its right subtree differ by at most 1. +_root: TreeNode * NULL value if tree is empty +AVLTree() +insert(value:int): void +find(value:int): int +delete_(value:int): void -_insertrec(t:treenode *, value:int): TreeNode * -_findrec(t:treenode *, value:int): TreeNode * -_deleterec(t:treenode *, value:int): TreeNode * -_deletemax(t:treenode *, item:int&): TreeNode * -_leftsinglerotate(t:treenode *, ): TreeNode * -_rightsinglerotate(t:treenode *, ): TreeNode * -_leftrightrotate(t :TreeNode *, ): TreeNode * -_rightleftrotate(t:treenode *, ): TreeNode *
AVL Instance Methods with Rebalancing Rotations A Call to the insert Method In this example, we have just inserted the value into an AVL Tree, violating the AVL property. (Why?) Throughout the rebalancing process, notice how the BST property is preserved: t First, calling insert with value results in a call to insertrec, the private, recursive, helper method: void AVLTree::insert(int value) root = insertrec( root, value); Calling insertrec: TreeNode *AVLTree:: insertrec(treenode* t, int value) if (t == NULL) t = new TreeNode(value, NULL, NULL); else if (value < t-> item) t-> left = insertrec(t-> left, value); if (getheight(t-> left) - getheight(t-> right) == ) //rebalance? // inserted into which subtree of left child? if (value < t-> left-> item) t = leftsinglerotate(t); // left subtree else t = rightleftrotate(t); // right subtree
After inserting where the BST property is satisfied, we test whether putting it into the left subtree has unbalanced the tree by making it too high. If it has, and if value < t-> left-> item is true, rebalance by calling t = leftsinglerotate(t);, otherwise by calling t = rightleftrotate(t);: In this case, we make the latter call. TreeNode *AVLTree:: rightleftrotate(treenode *t) t-> left = rightsinglerotate(t-> left); t = leftsinglerotate(t); return t; It begins with t-> left = rightsinglerotate(t-> left): TreeNode *AVLTree:: rightsinglerotate(treenode *t) TreeNode *grandparent = t; TreeNode *parent = t-> right; grandparent-> right = parent-> left; parent-> left = grandparent; t = parent; // adjust heights of grandparent, parent return t; t
After TreeNode *grandparent = t; TreeNode *parent = t-> right; t, grandparent parent After grandparent-> right = parent-> left; t, grandparent parent
After parent-> left = grandparent; t = parent; t, parent grandparent After return from rightsinglerotate(treenode *t), we are back in rightleftrotate(treenode *t), about to call leftsinglerotate(treenode *t) t
After TreeNode *grandparent = t; TreeNode *parent = t-> left; t, grandparent parent After grandparent-> left = parent-> right; parent t, grandparent 7
After parent-> right = grandparent; t = parent; t, parent grandparent After return from leftsinglerotate(treenode *t) t Exercises 1. Finish rotations, in the AVL Class code provided, for the remaining insert method cases.. Add code to perform rebalancing for deletion operations in the code provided.