Chapter 6 AVL Search Trees The efficiency of binary search tree - - PowerPoint PPT Presentation
Chapter 6 AVL Search Trees The efficiency of binary search tree - - PowerPoint PPT Presentation
CS 2412 Data Structures Chapter 6 AVL Search Trees The efficiency of binary search tree depends on the shape of the tree. If an ordered or almost ordered sequence of data are inserted to a binary tree, then the search is not efficient. ( O (
The efficiency of binary search tree depends on the shape of the tree.
- If an ordered or almost ordered sequence of data are inserted to
a binary tree, then the search is not efficient. (O(n)).
- If the inserted data is random, the tree is more efficient.
- An idea binary search tree is a “balanced” tree, for that the
search complexity is O(log n).
Data Structure 2016
- R. Wei
2
Definition An AVL tree is a binary tree that either is empty or consists of two AVL subtrees, TL and TR, whose heights differ by no more than 1. Let HL, HR denote the height of TL, TR respectively, then |HL − HR| ≤ 1. An AVL tree is also know as a height-balanced binary search tree. An AVL tree with HL = HR + 1 is called left high (LH), with HL = HR − 1 is called right high (RH), and with HL = HR is called equal (or even) high (EH).
Data Structure 2016
- R. Wei
3
Data Structure 2016
- R. Wei
4
Balancing trees When a node is inserted into a tree or deleted from a balanced tree, the resulting tree may be unbalanced. Some rotating methods are used in AVL to balance the tree.
- 1. Left of left: a subtree of a tree that is left high has also become
left high.
- 2. Right of right: a subtree of a tree that is right high has also
become right high.
- 3. Right of left: a subtree of a tree that is left high has become
right high.
- 4. Left of right: a subtree of a tree that is right high has become
left high.
Data Structure 2016
- R. Wei
5
Data Structure 2016
- R. Wei
6
Data Structure 2016
- R. Wei
7
Left of left One simple case is that the lowest subtree is not balanced. This case needs a rotation to right. Another case is that the subtree is balanced, but the whole tree is not balanced. In this case, we need to rotate the root to right. And we also need to move the right subtree of the subtree as a left subtree of the old root. Right of right is similar.
Data Structure 2016
- R. Wei
8
Data Structure 2016
- R. Wei
9
Data Structure 2016
- R. Wei
10
Right of left Suppose the root is left high and the left tree is right high. To balance this tree, we need first to do a left rotation and then do a right rotation making the left node the new root. Suppose an internal node is left high and its left subtree is right
- high. First rotate the left subtree of the node. Now the node in a
left of left situation, and we do the right rotation as the left of left case. Left of right is similar.
Data Structure 2016
- R. Wei
11
Data Structure 2016
- R. Wei
12
Data Structure 2016
- R. Wei
13
Algorithms for AVL AVL tree is a special kind BST. So some algorithms for BST can be used for AVL: such as search, retrieval, traversal etc. The insertion and deletion algorithm should be changed since the balance need to be checked constantly. Before insertion, AVL tree is balance. After inserting a node, a balance check may required.
- If the original tree is EH, then no rotation is needed.
- If the original tree is LH and the node is inserted to right
subtree, or if the original tree is RH and the node is inserted to left subtree, then no rotation is needed.
- Otherwise, we need to check if the resulting tree is balanced.
Data Structure 2016
- R. Wei
14
Data Structure 2016
- R. Wei
15
If the root is LH and a node has been inserted to the left subtree which is now taller (higher). Then the following algorithm is called. The algorithm for right balance is similar to left balance (mirrors of each other).
Data Structure 2016
- R. Wei
16
rotateRight: Make left subtree new root and the right subtree of the left subtree the left subtree of the original root.
Data Structure 2016
- R. Wei
17
Rotate left is similar.
Data Structure 2016
- R. Wei
18
Deletion Deletion is similar to that in BST. First find out the node needs to be delete. If the node is a leaf, then simply delete it. If the node is not a leaf, then we need to find out a node which can replace the deleting node. Similar to insertion of AVL, we also need to check balance after deleting a node. For example, if the deleted node is at left subtree, and the original tree is RH, then we need to check if the left tree is shorter after deletion.
Data Structure 2016
- R. Wei
19
Data Structure 2016
- R. Wei
20
Data Structure 2016
- R. Wei
21
Data Structure 2016
- R. Wei
22
Data Structure 2016
- R. Wei
23
Delete left balance is similar.
Data Structure 2016
- R. Wei
24
Adjusting the balance factor After an insertion, we need to adjust the balance factors for the nodes.
- If the root was EH before an insert, it is now high on the side
in witch the insert was made.
- If an insert was in the shorter subtree of a tree that was not
EH, the root is now EH.
- If an insert was in the higher subtree of a tree that was not
EH, the root must be rotated. The balance factor need to adjust after deletion in a similar way.
Data Structure 2016
- R. Wei
25
Implement AVL in C
#define LH +1 // Left High #define EH // Even High #define RH -1 // Right High typedef struct node { void* dataPtr; struct node* left; int bal; //LH of EH or RH struct node* right; } NODE; typedef struct { int count; int (*compare) (void* argu1, void* argu2); NODE* root; } AVL_TREE;
Data Structure 2016
- R. Wei
26
AVL_TREE* AVL_Create (int (*compare) (void* argu1, void* argu2)) { AVL_TREE* tree; tree = (AVL_TREE*) malloc (sizeof (AVL_TREE)); if (tree) { tree->root = NULL; tree->count = 0; tree->compare = compare; } // if return tree; } // AVL_Create
Data Structure 2016
- R. Wei
27
bool AVL_Insert (AVL_TREE* tree, void* dataInPtr) { NODE* newPtr; bool forTaller; newPtr = (NODE*)malloc(sizeof(NODE)); if (!newPtr) return false; newPtr->bal = EH; newPtr->right = NULL; newPtr->left = NULL; newPtr->dataPtr = dataInPtr; tree->root = _insert(tree, tree->root, newPtr, &forTaller); (tree->count)++; return true; } // AVL_Insert
Data Structure 2016
- R. Wei
28
NODE* _insert (AVL_TREE* tree, NODE* root, NODE* newPtr, bool* taller) { if (!root) { root = newPtr; *taller = true; return root; } // if NULL tree if (tree->compare(newPtr->dataPtr, root->dataPtr) < 0) { root->left = _insert(tree, root->left, newPtr, taller); if (*taller) switch (root->bal) { case LH: // Was left high--rotate
Data Structure 2016
- R. Wei
29
root = insLeftBal (root, taller); break; case EH: // Was balanced--now LH root->bal = LH; break; case RH: // Was right high--now EH root->bal = EH; *taller = false; break; } // switch return root; } // new < node else { root->right = _insert (tree, root->right, newPtr, taller); if (*taller) switch (root->bal)
Data Structure 2016
- R. Wei
30
{ case LH: // Was left high--now EH root->bal = EH; *taller = false; break; case EH: // Was balanced--now RH root->bal = RH; break; case RH: // Was right high--rotate root = insRightBal (root, taller); break; } // switch return root; } // else new data >= root data return root; } // _insert
Data Structure 2016
- R. Wei
31
NODE* insLeftBal (NODE* root, bool* taller) { NODE* rightTree; NODE* leftTree; leftTree = root->left; switch (leftTree->bal) { case LH: // Left High--Rotate Right root->bal = EH; leftTree->bal = EH; root = rotateRight (root); *taller = false; break; case EH: // This is an error printf ("\n\aError in insLeftBal\n"); exit (100); case RH: // Right High-Requires double rightTree = leftTree->right;
Data Structure 2016
- R. Wei
32
switch (rightTree->bal) { case LH: root->bal = RH; leftTree->bal = EH; break; case EH: root->bal = EH; leftTree->bal = EH; break; case RH: root->bal = EH; leftTree->bal = LH; break; } // switch rightTree rightTree->bal = EH; root->left = rotateLeft (leftTree); root = rotateRight (root); *taller = false; } // switch return root; }
Data Structure 2016
- R. Wei
33
NODE* rotateLeft (NODE* root) { NODE* tempPtr; tempPtr = root->right; root->right = tempPtr->left; tempPtr->left = root; return tempPtr; } // rotateLeft The program for rotateRight is similar.
Data Structure 2016
- R. Wei
34
bool AVL_Delete (AVL_TREE* tree, void* dltKey) { bool shorter; bool success; NODE* newRoot; newRoot = _delete (tree, tree->root, dltKey, &shorter, &success); if (success) { tree->root = newRoot; (tree->count)--; return true; } // if else return false; } // AVL_Delete
Data Structure 2016
- R. Wei
35
NODE* _delete (AVL_TREE* tree, NODE* root, void* dltKey, bool* shorter, bool* success) { NODE* dltPtr; NODE* exchPtr; NODE* newRoot; if (!root) { *shorter = false; *success = false; return NULL; } // if if (tree->compare(dltKey, root->dataPtr) < 0) { root->left = _delete (tree, root->left, dltKey, shorter, success);
Data Structure 2016
- R. Wei
36
if (*shorter) root = dltRightBal (root, shorter); } // if less else if (tree->compare(dltKey, root->dataPtr) > 0) { root->right = _delete (tree, root->right, dltKey, shorter, success); if (*shorter) root = dltLeftBal (root, shorter); } // if greater else { dltPtr = root; if (!root->right) // Only left subtree { newRoot = root->left;
Data Structure 2016
- R. Wei
37
*success = true; *shorter = true; free (dltPtr); return newRoot; // base case } // if true else if (!root->left) { newRoot = root->right; *success = true; *shorter = true; free (dltPtr); return newRoot; // base case } // if else { exchPtr = root->left; while (exchPtr->right)
Data Structure 2016
- R. Wei
38
exchPtr = exchPtr->right; root->dataPtr = exchPtr->dataPtr; root->left = _delete (tree, root->left, exchPtr->dataPtr, shorter, success); if (*shorter) root = dltRightBal (root, shorter); } // else } // equal node return root; } // _delete
Data Structure 2016
- R. Wei
39
NODE* dltRightBal (NODE* root, bool* shorter) { NODE* rightTree; NODE* leftTree; switch (root->bal) { case LH: // Deleted Left--Now balanced root->bal = EH; break; case EH: // Now Right high root->bal = RH; *shorter = false; break; case RH: // Right High - Rotate Left rightTree = root->right; if (rightTree ->bal == LH) {letTree = rightTree->left; switch (leftTree->bal)
Data Structure 2016
- R. Wei
40
{ case LH: rightTree->bal = RH; root->bal = EH; break; case EH: root->bal = EH; rightTree->bal = EH; break; case RH: root->bal = LH; rightTree->bal = EH; break; } // switch leftTree->bal = EH; root->right = rotateRight (rightTree); root = rotateLeft (root); } // if rightTree->bal == LH else {
Data Structure 2016
- R. Wei
41
switch (rightTree->bal) { case LH: case RH: root->bal = EH; rightTree->bal = EH; break; case EH: root->bal = RH; rightTree->bal = LH; *shorter = false; break; } // switch rightTree->bal root = rotateLeft (root); } // else } // switch return root; } // dltRightBal
Data Structure 2016
- R. Wei
42
void* AVL_Retrieve (AVL_TREE* tree, void* keyPtr) { if (tree->root) return _retrieve (tree, keyPtr, tree->root); else return NULL; } // AVL_Retrieve
Data Structure 2016
- R. Wei
43
void* _retrieve (AVL_TREE* tree, void* keyPtr, NODE* root) { if (root) { if (tree->compare(keyPtr, root->dataPtr) < 0) return _retrieve(tree, keyPtr, root->left); else if (tree->compare(keyPtr, root->dataPtr) > 0) return _retrieve(tree, keyPtr, root->right); else return root->dataPtr; } // if root else return NULL; } // _retrieve
Data Structure 2016
- R. Wei
44
void AVL_Traverse (AVL_TREE* tree, void (*process) (void* dataPtr)) { // Statements _traversal (tree->root, process); return; } // end AVL_Traverse
Data Structure 2016
- R. Wei
45
void _traversal (NODE* root, void (*process) (void* dataPtr)) { // Statements if (root) { _traversal (root->left, process); process (root->dataPtr); _traversal (root->right, process); } // if return; } // _traversal
Data Structure 2016
- R. Wei
46
AVL_TREE* AVL_Destroy (AVL_TREE* tree) { // Statements if (tree) _destroy (tree->root); // All nodes deleted. Free structure free (tree); return NULL; } // AVL_Destroy
Data Structure 2016
- R. Wei
47
void _destroy (NODE* root) { // Statements if (root) { _destroy (root->left); free (root->dataPtr); _destroy (root->right); free (root); } // if return; } // _destroy
Data Structure 2016
- R. Wei
48
NODE* insRightBal (NODE* root, bool* taller) { NODE *rightTree; NODE *leftTree; rightTree = root->right; switch (rightTree->bal ) { case LH: // Left High - Requires double rotation: leftTree = rightTree-> left; switch (leftTree->bal ) { case RH: root->bal = LH; rightTree->bal = EH; break; case EH: root->bal = EH; rightTree->bal = EH; break; case LH: root->bal = EH; rightTree->bal = RH; break; } // switch
Data Structure 2016
- R. Wei
49
leftTree->bal = EH; root->right = rotateRight (rightTree ); root = rotateLeft (root ); *taller = false; break; case EH: printf( "\n\a\aError in rightBalance\n" ); break; root->bal = EH; taller = false; break; case RH: root->bal = EH; rightTree->bal = EH; root = rotateLeft ( root ); *taller = false; break; } // switch return root; } // insRightBal
Data Structure 2016
- R. Wei
50
NODE* dltLeftBal ( NODE* root, bool* smaller ) { NODE *rightTree; NODE *leftTree; switch ( root->bal ) { case RH: root->bal = EH; break; case EH: root->bal = LH; *smaller = false; break; case LH: leftTree = root->left; switch ( leftTree->bal ) { case LH: case EH: if ( leftTree->bal == EH ) { root->bal = LH;
Data Structure 2016
- R. Wei
51
leftTree->bal = RH; *smaller = false; } else { root->bal = EH; leftTree->bal = EH; } root = rotateRight (root); break; case RH: // Double Rotation rightTree = leftTree->right; switch ( rightTree->bal ) { case LH: root->bal = RH; leftTree->bal = EH; break; case EH: root->bal = EH;
Data Structure 2016
- R. Wei
52
leftTree->bal = EH; break; case RH: root->bal = EH; leftTree->bal = LH; break; } // switch rightTree->bal = EH; root->left = rotateLeft (leftTree); root = rotateRight (root); break; } // switch : leftTree->bal } // switch : root->bal return root; } // dltLeftBalance
Data Structure 2016
- R. Wei
53
void AVL_Print (AVL_TREE* tree); void _print (NODE* root, int level); void AVL_Print (AVL_TREE* tree) { void _print (NODE* root, int level); _print (tree->root, 0); return; } // AVL_PRINT void _print (NODE* root, int level) { int i; if ( root ) { _print ( root->right, level + 1 );
Data Structure 2016
- R. Wei
54
printf( "bal %3d: Level: %3d", root->bal, level ); for (i = 0; i <= level; i++ ) printf ("...." ); printf( "%3d", *(int *)(root->dataPtr) ); if (root->bal == LH) printf( " (LH)\n"); else if (root->bal == RH) printf( " (RH)\n"); else printf( " (EH)\n"); _print ( root->left, level + 1 ); } // if return; } // print *
Data Structure 2016
- R. Wei
55
Example Count words Uses an AVL tree to count the number of times each words in a
- document. For each time a word is read, search the tree to see if
the tree has an node containing the word. If the word is found, then increase the count of the word. Otherwise insert a new node containing the word. We want to use the ADT AVL C program introduced previously.
Data Structure 2016
- R. Wei
56
First we define the data of the node as below. typedef struct { char word[51]; // One word int count; } DATA; Then we construct the system. We can use a structured method to construct the system, i.e., construct it top-down. So the main function is simple, which contains main steps. Then for each step, we give more detailed construction.
Data Structure 2016
- R. Wei
57
int main (void) { AVL_TREE* wordList; printf("Start count words in document\n"); wordList = AVL_Create (compareWords); buildList (wordList); printList (wordList); printf("End count words\n"); return 0; } // main
Data Structure 2016
- R. Wei
58
void buildList (AVL_TREE* wordList) { char fileName[25]; FILE* fpWords; bool success; DATA* aWord; DATA newWord; printf("Enter name of file to be processed: "); scanf ("%24s", fileName); fpWords = fopen (fileName, "r"); if (!fpWords) { printf("%-s could not be opened\a\n",fileName); printf("Please verify name and try again.\n"); exit (100); } // !fpWords
Data Structure 2016
- R. Wei
59
while (getWord (&newWord, fpWords)) { aWord = AVL_Retrieve(wordList, &(newWord)); if (aWord) (aWord->count)++; else { aWord = (DATA*) malloc (sizeof (DATA)); if (!aWord) { printf("Error 120 in buildList\n"); exit (120); } // if *aWord = newWord; aWord->count = 1; success = AVL_Insert (wordList, aWord);
Data Structure 2016
- R. Wei
60
if (!success) { printf("Error 121 in buildList\a\n"); exit (121); } // if overflow test } // else } // while printf("End AVL Tree\n"); return; } // buildList
Data Structure 2016
- R. Wei
61
bool getWord (DATA* aWord, FILE* fpWords) { char strIn[51]; int ioResult; int lastChar; ioResult = fscanf(fpWords, "%50s", strIn); if (ioResult != 1) return false; // Copy and remove punctuation at end of word. strcpy (aWord->word, strIn); lastChar = strlen(aWord->word) - 1; if (ispunct(aWord->word[lastChar])) aWord->word[lastChar] = ’\0’; return true; } // getWord
Data Structure 2016
- R. Wei
62
int compareWords (void* arguPtr, void* listPtr) { DATA arguValue; DATA listValue; arguValue = *(DATA*)arguPtr; listValue = *(DATA*)listPtr; return (strcmp(arguValue.word, listValue.word)); } // compare
Data Structure 2016
- R. Wei
63
void printList (AVL_TREE* wordList) { printf("\nWords found in list\n"); AVL_Traverse (wordList, printWord); printf("\nEnd of word list\n"); return; } // printList void printWord (void* aWord) { // Statements printf("%-25s %3d\n", ((DATA*)aWord)->word, ((DATA*)aWord)->count); return; } // printWord
Data Structure 2016
- R. Wei
64