Chapter 6 AVL Search Trees The efficiency of binary search tree - - PowerPoint PPT Presentation

chapter 6 avl search trees the efficiency of binary
SMART_READER_LITE
LIVE PREVIEW

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 (


slide-1
SLIDE 1

CS 2412 Data Structures

Chapter 6 AVL Search Trees

slide-2
SLIDE 2

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

slide-3
SLIDE 3

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

slide-4
SLIDE 4

Data Structure 2016

  • R. Wei

4

slide-5
SLIDE 5

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

slide-6
SLIDE 6

Data Structure 2016

  • R. Wei

6

slide-7
SLIDE 7

Data Structure 2016

  • R. Wei

7

slide-8
SLIDE 8

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

slide-9
SLIDE 9

Data Structure 2016

  • R. Wei

9

slide-10
SLIDE 10

Data Structure 2016

  • R. Wei

10

slide-11
SLIDE 11

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

slide-12
SLIDE 12

Data Structure 2016

  • R. Wei

12

slide-13
SLIDE 13

Data Structure 2016

  • R. Wei

13

slide-14
SLIDE 14

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

slide-15
SLIDE 15

Data Structure 2016

  • R. Wei

15

slide-16
SLIDE 16

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

slide-17
SLIDE 17

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

slide-18
SLIDE 18

Rotate left is similar.

Data Structure 2016

  • R. Wei

18

slide-19
SLIDE 19

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

slide-20
SLIDE 20

Data Structure 2016

  • R. Wei

20

slide-21
SLIDE 21

Data Structure 2016

  • R. Wei

21

slide-22
SLIDE 22

Data Structure 2016

  • R. Wei

22

slide-23
SLIDE 23

Data Structure 2016

  • R. Wei

23

slide-24
SLIDE 24

Delete left balance is similar.

Data Structure 2016

  • R. Wei

24

slide-25
SLIDE 25

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

slide-26
SLIDE 26

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

slide-27
SLIDE 27

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

slide-28
SLIDE 28

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

slide-29
SLIDE 29

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

slide-30
SLIDE 30

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

slide-31
SLIDE 31

{ 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

slide-32
SLIDE 32

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

slide-33
SLIDE 33

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

slide-34
SLIDE 34

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

slide-35
SLIDE 35

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

slide-36
SLIDE 36

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

slide-37
SLIDE 37

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

slide-38
SLIDE 38

*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

slide-39
SLIDE 39

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

slide-40
SLIDE 40

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

slide-41
SLIDE 41

{ 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

slide-42
SLIDE 42

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

slide-43
SLIDE 43

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

slide-44
SLIDE 44

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

slide-45
SLIDE 45

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

slide-46
SLIDE 46

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

slide-47
SLIDE 47

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

slide-48
SLIDE 48

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

slide-49
SLIDE 49

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

slide-50
SLIDE 50

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

slide-51
SLIDE 51

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

slide-52
SLIDE 52

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

slide-53
SLIDE 53

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

slide-54
SLIDE 54

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

slide-55
SLIDE 55

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

slide-56
SLIDE 56

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

slide-57
SLIDE 57

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

slide-58
SLIDE 58

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

slide-59
SLIDE 59

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

slide-60
SLIDE 60

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

slide-61
SLIDE 61

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

slide-62
SLIDE 62

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

slide-63
SLIDE 63

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

slide-64
SLIDE 64

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