Presentation is loading. Please wait.

Presentation is loading. Please wait.

1 C++ Classes and Data Structures Jeffrey S. Childs Chapter 15 Other Data Structures Jeffrey S. Childs Clarion University of PA © 2008, Prentice Hall.

Similar presentations


Presentation on theme: "1 C++ Classes and Data Structures Jeffrey S. Childs Chapter 15 Other Data Structures Jeffrey S. Childs Clarion University of PA © 2008, Prentice Hall."— Presentation transcript:

1 1 C++ Classes and Data Structures Jeffrey S. Childs Chapter 15 Other Data Structures Jeffrey S. Childs Clarion University of PA © 2008, Prentice Hall

2 2 Binary Search Trees A binary search tree is a binary tree that allows us to search for values that can be anywhere in the tree Usually, we search for a certain key value, and once we find the node that contains it, we retrieve the rest of the info at that node Therefore, we assume that all values searched for in a binary search tree are distinct

3 3 Properties of Binary Search Trees A binary search tree does not have to be a complete binary tree (like a heap) For any particular node, –the key in its left child (if any) is less than its key –the key in its right child (if any) is greater than its key

4 4 Binary Search Tree Node template BSTNode { DataType info; BSTNode *left; BSTNode *right; }; The implementation of a binary search tree usually just maintains a single pointer in the private section called root, to point to the root node.

5 5 Inserting Nodes Into a BST 37, 2, 45, 48, 41, 29, 20, 30, 49, 7 Objects that need to be inserted (only key values are shown): root: NULL BST starts off empty

6 6 Inserting Nodes Into a BST (cont.) 37, 2, 45, 48, 41, 29, 20, 30, 49, 7 root 37

7 7 Inserting Nodes Into a BST (cont.) 2, 45, 48, 41, 29, 20, 30, 49, 7 root 37

8 8 Inserting Nodes Into a BST (cont.) 2, 45, 48, 41, 29, 20, 30, 49, 7 root 37

9 9 Inserting Nodes Into a BST (cont.) 2, 45, 48, 41, 29, 20, 30, 49, 7 root 37 2 < 37, so insert 2 on the left side of 37

10 10 Inserting Nodes Into a BST (cont.) 2, 45, 48, 41, 29, 20, 30, 49, 7 root 37 2

11 11 Inserting Nodes Into a BST (cont.) 45, 48, 41, 29, 20, 30, 49, 7 root 37 2

12 12 Inserting Nodes Into a BST (cont.) 45, 48, 41, 29, 20, 30, 49, 7 root 37 2

13 13 Inserting Nodes Into a BST (cont.) 45, 48, 41, 29, 20, 30, 49, 7 root 37 2 45 > 37, so insert it at the right of 37

14 14 Inserting Nodes Into a BST (cont.) 45, 48, 41, 29, 20, 30, 49, 7 root 37 2 45

15 15 Inserting Nodes Into a BST (cont.) 48, 41, 29, 20, 30, 49, 7 root 37 2 45

16 16 Inserting Nodes Into a BST (cont.) 48, 41, 29, 20, 30, 49, 7 root 37 2 45

17 17 Inserting Nodes Into a BST (cont.) 48, 41, 29, 20, 30, 49, 7 root 37 2 45 When comparing, we always start at the root node

18 18 Inserting Nodes Into a BST (cont.) 48, 41, 29, 20, 30, 49, 7 root 37 2 45 48 > 37, so look to the right

19 19 Inserting Nodes Into a BST (cont.) 48, 41, 29, 20, 30, 49, 7 root 37 2 45 48 > 37, so look to the right

20 20 Inserting Nodes Into a BST (cont.) 48, 41, 29, 20, 30, 49, 7 root 37 2 45 This time, there is a node already to the right of the root node. We then compare 48 to this node

21 21 Inserting Nodes Into a BST (cont.) 48, 41, 29, 20, 30, 49, 7 root 37 2 45 48 > 45, and 45 has no right child, so we insert 48 on the right of 45

22 22 Inserting Nodes Into a BST (cont.) 48, 41, 29, 20, 30, 49, 7 root 37 2 45 48

23 23 Inserting Nodes Into a BST (cont.) 41, 29, 20, 30, 49, 7 root 37 2 45 48

24 24 Inserting Nodes Into a BST (cont.) 41, 29, 20, 30, 49, 7 root 37 2 45 48

25 25 Inserting Nodes Into a BST (cont.) 41, 29, 20, 30, 49, 7 root 37 2 45 48 41 > 37, so look to the right

26 26 Inserting Nodes Into a BST (cont.) 41, 29, 20, 30, 49, 7 root 37 2 45 48

27 27 Inserting Nodes Into a BST (cont.) 41, 29, 20, 30, 49, 7 root 37 2 45 48 41 < 45, so look to the left – there is no left child, so insert

28 28 Inserting Nodes Into a BST (cont.) 41, 29, 20, 30, 49, 7 root 37 2 45 48 41

29 29 Inserting Nodes Into a BST (cont.) 29, 20, 30, 49, 7 root 37 2 45 48 41

30 30 Inserting Nodes Into a BST (cont.) 29, 20, 30, 49, 7 root 37 2 45 48 41

31 31 Inserting Nodes Into a BST (cont.) 29, 20, 30, 49, 7 root 37 2 45 48 41 29 < 37

32 32 Inserting Nodes Into a BST (cont.) 29, 20, 30, 49, 7 root 37 2 45 48 41

33 33 Inserting Nodes Into a BST (cont.) 29, 20, 30, 49, 7 root 37 2 45 48 41 29 > 2

34 34 Inserting Nodes Into a BST (cont.) 29, 20, 30, 49, 7 root 37 2 45 48 4129

35 35 Inserting Nodes Into a BST (cont.) 20, 30, 49, 7 root 37 2 45 48 4129

36 36 Inserting Nodes Into a BST (cont.) 20, 30, 49, 7 root 37 2 45 48 4129

37 37 Inserting Nodes Into a BST (cont.) 20, 30, 49, 7 root 37 2 45 48 4129 20 < 37

38 38 Inserting Nodes Into a BST (cont.) 20, 30, 49, 7 root 37 2 45 48 4129

39 39 Inserting Nodes Into a BST (cont.) 20, 30, 49, 7 root 37 2 45 48 4129 20 > 2

40 40 Inserting Nodes Into a BST (cont.) 20, 30, 49, 7 root 37 2 45 48 4129

41 41 Inserting Nodes Into a BST (cont.) 20, 30, 49, 7 root 37 2 45 48 4129 20 < 29

42 42 Inserting Nodes Into a BST (cont.) 20, 30, 49, 7 root 37 2 45 48 4129 20

43 43 Inserting Nodes Into a BST (cont.) 30, 49, 7 root 37 2 45 48 4129 20

44 44 Inserting Nodes Into a BST (cont.) 30, 49, 7 root 37 2 45 48 4129 20

45 45 Inserting Nodes Into a BST (cont.) 30, 49, 7 root 37 2 45 48 4129 20 30 < 37

46 46 Inserting Nodes Into a BST (cont.) 30, 49, 7 root 37 2 45 48 4129 20

47 47 Inserting Nodes Into a BST (cont.) 30, 49, 7 root 37 2 45 48 4129 20 30 > 2

48 48 Inserting Nodes Into a BST (cont.) 30, 49, 7 root 37 2 45 48 4129 20

49 49 Inserting Nodes Into a BST (cont.) 30, 49, 7 root 37 2 45 48 4129 20 30 > 29

50 50 Inserting Nodes Into a BST (cont.) 30, 49, 7 root 37 2 45 48 4129 2030

51 51 Inserting Nodes Into a BST (cont.) 49, 7 root 37 2 45 48 4129 2030

52 52 Inserting Nodes Into a BST (cont.) 49, 7 root 37 2 45 48 4129 2030

53 53 Inserting Nodes Into a BST (cont.) 49, 7 root 37 2 45 48 4129 2030 49 > 37

54 54 Inserting Nodes Into a BST (cont.) 49, 7 root 37 2 45 48 4129 2030

55 55 Inserting Nodes Into a BST (cont.) 49, 7 root 37 2 45 48 4129 2030 49 > 45

56 56 Inserting Nodes Into a BST (cont.) 49, 7 root 37 2 45 48 4129 2030

57 57 Inserting Nodes Into a BST (cont.) 49, 7 root 37 2 45 48 4129 2030 49 > 48

58 58 Inserting Nodes Into a BST (cont.) 49, 7 root 37 2 45 48 4129 203049

59 59 Inserting Nodes Into a BST (cont.) 7 root 37 2 45 48 4129 203049

60 60 Inserting Nodes Into a BST (cont.) 7 root 37 2 45 48 4129 203049

61 61 Inserting Nodes Into a BST (cont.) 7 root 37 2 45 48 4129 203049 7 < 37

62 62 Inserting Nodes Into a BST (cont.) 7 root 37 2 45 48 4129 203049

63 63 Inserting Nodes Into a BST (cont.) 7 root 37 2 45 48 4129 203049 7 > 2

64 64 Inserting Nodes Into a BST (cont.) 7 root 37 2 45 48 4129 203049

65 65 Inserting Nodes Into a BST (cont.) 7 root 37 2 45 48 4129 203049 7 < 29

66 66 Inserting Nodes Into a BST (cont.) 7 root 37 2 45 48 4129 203049

67 67 Inserting Nodes Into a BST (cont.) 7 root 37 2 45 48 4129 203049 7 < 20

68 68 Inserting Nodes Into a BST (cont.) 7 root 37 2 45 48 4129 203049 7

69 69 Inserting Nodes Into a BST (cont.) root 37 2 45 48 4129 203049 7

70 70 Inserting Nodes Into a BST (cont.) root 37 2 45 48 4129 203049 All elements have been inserted 7

71 71 Searching for a Key in a BST root 37 2 45 48 4129 203049 Searching for a key in a BST uses the same logic 7

72 72 Searching for a Key in a BST (cont.) root 37 2 45 48 4129 203049 Key to search for: 29 7

73 73 Searching for a Key in a BST (cont.) root 37 2 45 48 4129 203049 Key to search for: 29 7

74 74 Searching for a Key in a BST (cont.) root 37 2 45 48 4129 203049 Key to search for: 29 29 < 37 7

75 75 Searching for a Key in a BST (cont.) root 37 2 45 48 4129 203049 Key to search for: 29 7

76 76 Searching for a Key in a BST (cont.) root 37 2 45 48 4129 203049 Key to search for: 29 29 > 2 7

77 77 Searching for a Key in a BST (cont.) root 37 2 45 48 4129 203049 Key to search for: 29 7

78 78 Searching for a Key in a BST (cont.) root 37 2 45 48 4129 203049 Key to search for: 29 29 == 29 FOUND IT! 7

79 79 Searching for a Key in a BST (cont.) root 37 2 45 48 4129 203049 7

80 80 Searching for a Key in a BST (cont.) root 37 2 45 48 4129 203049 Key to search for: 3 7

81 81 Searching for a Key in a BST (cont.) root 37 2 45 48 4129 203049 Key to search for: 3 7

82 82 Searching for a Key in a BST (cont.) root 37 2 45 48 4129 203049 Key to search for: 3 3 < 37 7

83 83 Searching for a Key in a BST (cont.) root 37 2 45 48 4129 203049 Key to search for: 3 7

84 84 Searching for a Key in a BST (cont.) root 37 2 45 48 4129 203049 Key to search for: 3 3 > 2 7

85 85 Searching for a Key in a BST (cont.) root 37 2 45 48 4129 203049 Key to search for: 3 7

86 86 Searching for a Key in a BST (cont.) root 37 2 45 48 4129 203049 Key to search for: 3 3 < 29 7

87 87 Searching for a Key in a BST (cont.) root 37 2 45 48 4129 203049 Key to search for: 3 7

88 88 Searching for a Key in a BST (cont.) root 37 2 45 48 4129 203049 Key to search for: 3 3 < 20 7

89 89 Searching for a Key in a BST (cont.) root 37 2 45 48 4129 203049 Key to search for: 3 7

90 90 Searching for a Key in a BST (cont.) root 37 2 45 48 4129 203049 Key to search for: 3 3 < 7 7

91 91 Searching for a Key in a BST (cont.) root 37 2 45 48 4129 203049 Key to search for: 3 When the child pointer you want to follow is set to NULL, the key you are looking for is not in the BST 7

92 92 Time Complexities If the binary search tree happens to be a complete binary tree: –the time for insertion is  ( lg n ) –the time for the search is O( lg n ) –similar to swapping upwards or downwards through the heap However, we could run into some bad luck…

93 93 Bad Luck 2, 7, 20, 29, 30, 37, 41, 45, 48, 49 root 2 7 20 29 30 37 41 45 48 49 Exactly the same keys were inserted into this BST – but they were inserted in a different order (the order shown below)

94 94 Bad Luck (cont.) 2, 7, 20, 29, 30, 37, 41, 45, 48, 49 root 2 7 20 29 30 37 41 45 48 49 This is some bad luck, but a BST can be formed this way

95 95 Bad Luck (cont.) 2, 7, 20, 29, 30, 37, 41, 45, 48, 49 root 2 7 20 29 30 37 41 45 48 49 Using the “tightest” possible big-oh notation, the insertion and search time is O( n )

96 96 Balanced vs. Unbalanced If a BST takes  ( lg n ) time for insertion, and O( lg n ) time for a search, we say it is a balanced binary search tree If a BST take O( n ) time for insertion and searching, we say it is an unbalanced binary search tree These definitions assume the tightest possible big-oh notation

97 97 Deleting a BST Node Deleting a node in a BST is a little tricky – it has to be deleted so that the resulting structure is still a BST with each node greater than its left child and less than its right child Deleting a node is handled differently depending on whether the node: –has no children –has one child –has two children

98 98 Deletion Case 1: No Children root 37 2 45 48 4129 203049 Node 49 has no children – to delete it, we just remove it

99 99 Deletion Case 1: No Children (cont.) root 37 2 45 48 4129 2030

100 100 Deletion Case 2: One Child root 37 2 45 48 4129 203049 Node 48 has one child – to delete it, we just splice it out

101 101 Deletion Case 2: One Child (cont.) root 37 2 45 48 4129 203049 Node 48 has one child – to delete it, we just splice it out

102 102 Deletion Case 2: One Child (cont.) root 37 2 45 4129 203049

103 103 Deletion Case 2: One Child (cont.) root 37 2 45 48 4129 203049 Another example: node 2 has one child – to delete it we also splice it out

104 104 Deletion Case 2: One Child (cont.) root 37 2 45 48 4129 203049 Another example: node 2 has one child – to delete it we also splice it out

105 105 Deletion Case 2: One Child (cont.) root 37 45 48 4129 203049

106 106 Deletion Case 3: Two Children root 37 2 45 48 4129 203049 Node 37 has two children…

107 107 Deletion Case 3: Two Children (cont.) root 37 2 45 48 4129 203049 to delete it, first we find the greatest node in its left subtree

108 108 Deletion Case 3: Two Children (cont.) root 37 2 45 48 4129 203049 First, we go to the left once, then follow the right pointers as far as we can to delete it, first we find the greatest node in its left subtree

109 109 Deletion Case 3: Two Children (cont.) root 37 2 45 48 4129 203049 to delete it, first we find the greatest node in its left subtree First, we go to the left once, then follow the right pointers as far as we can

110 110 Deletion Case 3: Two Children (cont.) root 37 2 45 48 4129 203049 to delete it, first we find the greatest node in its left subtree First, we go to the left once, then follow the right pointers as far as we can

111 111 Deletion Case 3: Two Children (cont.) root 37 2 45 48 4129 203049 to delete it, first we find the greatest node in its left subtree First, we go to the left once, then follow the right pointers as far as we can

112 112 Deletion Case 3: Two Children (cont.) root 37 2 45 48 4129 203049 30 is the greatest node in the left subtree of node 37 First, we go to the left once, then follow the right pointers as far as we can

113 113 Deletion Case 3: Two Children (cont.) root 37 2 45 48 4129 203049 Next, we copy the object at node 30 into node 37

114 114 Deletion Case 3: Two Children (cont.) root 37 2 45 48 4129 203049 Next, we copy the object at node 30 into node 37

115 115 Deletion Case 3: Two Children (cont.) root 30 2 45 48 4129 203049 Next, we copy the object at node 30 into node 37

116 116 Deletion Case 3: Two Children (cont.) root 30 2 45 48 4129 203049 Finally, we delete the lower red node using case 1 or case 2 deletion

117 117 Deletion Case 3: Two Children (cont.) root 30 2 45 48 4129 2049

118 118 Deletion Case 3: Two Children (cont.) root 30 2 45 48 4129 2049 Let’s delete node 30 now

119 119 Deletion Case 3: Two Children (cont.) root 30 2 45 48 4129 2049

120 120 Deletion Case 3: Two Children (cont.) root 30 2 45 48 4129 2049

121 121 Deletion Case 3: Two Children (cont.) root 30 2 45 48 4129 2049 The greatest node in the left subtree of node 30

122 122 Deletion Case 3: Two Children (cont.) root 30 2 45 48 4129 2049 The greatest node in the left subtree of node 30

123 123 Deletion Case 3: Two Children (cont.) root 29 2 45 48 4129 2049 The greatest node in the left subtree of node 30

124 124 Deletion Case 3: Two Children (cont.) root 29 2 45 48 4129 2049 This time, the lower red node has a child – to delete it we use case 2 deletion

125 125 Deletion Case 3: Two Children (cont.) root 29 2 45 48 4129 2049 This time, the lower red node has a child – to delete it we use case 2 deletion

126 126 Deletion Case 3: Two Children (cont.) root 29 2 45 48 41 2049

127 127 Deletion Time Complexity In all cases, we must find the node we wish to delete first, using the standard search method. Finding the greatest node in the left subtree is just a continuation of a path down the BST For balanced BST’s, the time complexity for deletion is O( lg n ) in all 3 cases For unbalanced BST’s, the time complexity is O( n ) in all 3 cases

128 128 Why Use BST’s? Hash tables can search in  ( 1 ) time, so why use BST’s? BST’s have the ability to provide all keys in order, in  ( n ) time To do so, it uses a recursive function called InOrder2, and a driver for the recursive function called InOrder…

129 129 1 template 2 bool BinarySearchTree::InOrder( Array & arr ) 3 { 4if ( size == 0 ) 5return false; 6arr.changeSize( size ); 7int i = 0; 8InOrder2( root, arr, i ); 9return true; 10 } The client uses the driver called InOrder, passing in an Array by reference, which will contain the objects in order by key after returning from InOrder Getting Elements In Order

130 130 1 template 2 bool BinarySearchTree::InOrder( Array & arr ) 3 { 4if ( size == 0 ) 5return false; 6arr.changeSize( size ); 7int i = 0; 8InOrder2( root, arr, i ); 9return true; 10 } If the BST has no elements, false is returned Getting Elements In Order (cont.)

131 131 1 template 2 bool BinarySearchTree::InOrder( Array & arr ) 3 { 4if ( size == 0 ) 5return false; 6arr.changeSize( size ); 7int i = 0; 8InOrder2( root, arr, i ); 9return true; 10 } The size of the Array is changed, so that it contains enough elements for all the nodes in the BST – the client may have set the size of the Array correctly, but we like to play it safe Getting Elements In Order (cont.)

132 132 1 template 2 bool BinarySearchTree::InOrder( Array & arr ) 3 { 4if ( size == 0 ) 5return false; 6arr.changeSize( size ); 7int i = 0; 8InOrder2( root, arr, i ); 9return true; 10 } i is used to index the Array Getting Elements In Order (cont.)

133 133 1 template 2 bool BinarySearchTree::InOrder( Array & arr ) 3 { 4if ( size == 0 ) 5return false; 6arr.changeSize( size ); 7int i = 0; 8InOrder2( root, arr, i ); 9return true; 10 } The recursive function InOrder2 is called, passing arr by reference – when the top-level InOrder2 returns, arr will contain the objects with keys in sorted order Getting Elements In Order (cont.)

134 134 1 template 2 bool BinarySearchTree::InOrder( Array & arr ) 3 { 4if ( size == 0 ) 5return false; 6arr.changeSize( size ); 7int i = 0; 8InOrder2( root, arr, i ); 9return true; 10 } So let’s now focus on the InOrder2 function… Getting Elements In Order (cont.)

135 135 1 template 2 void BinarySearchTree::InOrder2( 3 BSTNode *ptr, Array & arr, int & i ) 4 { 5if ( ptr != NULL ) { 6InOrder2( ptr->left, arr, i ); 7arr[ i ] = ptr->info; 8i++; 9InOrder2( ptr->right, arr, i ); 10} 11 } Getting Elements In Order (cont.)

136 136 1 template 2 void BinarySearchTree::InOrder2( 3 BSTNode *ptr, Array & arr, int & i ) 4 { 5if ( ptr != NULL ) { 6InOrder2( ptr->left, arr, i ); 7arr[ i ] = ptr->info; 8i++; 9InOrder2( ptr->right, arr, i ); 10} 11 } This is the only line which places info in the array… Getting Elements In Order (cont.)

137 137 1 template 2 void BinarySearchTree::InOrder2( 3 BSTNode *ptr, Array & arr, int & i ) 4 { 5if ( ptr != NULL ) { 6InOrder2( ptr->left, arr, i ); 7arr[ i ] = ptr->info; 8i++; 9InOrder2( ptr->right, arr, i ); 10} 11 } then i is incremented Getting Elements In Order (cont.)

138 138 1 template 2 void BinarySearchTree::InOrder2( 3 BSTNode *ptr, Array & arr, int & i ) 4 { 5if ( ptr != NULL ) { 6InOrder2( ptr->left, arr, i ); 7arr[ i ] = ptr->info; 8i++; 9InOrder2( ptr->right, arr, i ); 10} 11 } i is passed by reference, so every time it is incremented, the calling function knows about it Getting Elements In Order (cont.)

139 139 1 template 2 void BinarySearchTree::InOrder2( 3 BSTNode *ptr, Array & arr, int & i ) 4 { 5if ( ptr != NULL ) { 6InOrder2( ptr->left, arr, i ); 7arr[ i ] = ptr->info; 8i++; 9InOrder2( ptr->right, arr, i ); 10} 11 } The base case occurs when ptr is NULL – just returns Getting Elements In Order (cont.)

140 140 1 template 2 void BinarySearchTree::InOrder2( 3 BSTNode *ptr, Array & arr, int & i ) 4 { 5if ( ptr != NULL ) { 6InOrder2( ptr->left, arr, i ); 7arr[ i ] = ptr->info; 8i++; 9InOrder2( ptr->right, arr, i ); 10} 11 } There are two recursive calls under the if – the first advances the pointer to the left child… Getting Elements In Order (cont.)

141 141 1 template 2 void BinarySearchTree::InOrder2( 3 BSTNode *ptr, Array & arr, int & i ) 4 { 5if ( ptr != NULL ) { 6InOrder2( ptr->left, arr, i ); 7arr[ i ] = ptr->info; 8i++; 9InOrder2( ptr->right, arr, i ); 10} 11 } and the second advances the pointer to the right child Getting Elements In Order (cont.)

142 142 1 template 2 void BinarySearchTree::InOrder2( 3 BSTNode *ptr, Array & arr, int & i ) 4 { 5if ( ptr != NULL ) { 6InOrder2( ptr->left, arr, i ); 7arr[ i ] = ptr->info; 8i++; 9InOrder2( ptr->right, arr, i ); 10} 11 } Notice that this will be the same ptr in both cases Getting Elements In Order (cont.)

143 143 1 template 2 void BinarySearchTree::InOrder2( 3 BSTNode *ptr, Array & arr, int & i ) 4 { 5if ( ptr != NULL ) { 6InOrder2( ptr->left, arr, i ); 7arr[ i ] = ptr->info; 8i++; 9InOrder2( ptr->right, arr, i ); 10} 11 } Notice that each recursive call approaches the base case… Getting Elements In Order (cont.)

144 144 1 template 2 void BinarySearchTree::InOrder2( 3 BSTNode *ptr, Array & arr, int & i ) 4 { 5if ( ptr != NULL ) { 6InOrder2( ptr->left, arr, i ); 7arr[ i ] = ptr->info; 8i++; 9InOrder2( ptr->right, arr, i ); 10} 11 } it goes down one level through the tree, and so it must get closer to the case where ptr->left or ptr- >right is NULL Getting Elements In Order (cont.)

145 145 1 template 2 void BinarySearchTree::InOrder2( 3 BSTNode *ptr, Array & arr, int & i ) 4 { 5if ( ptr != NULL ) { 6InOrder2( ptr->left, arr, i ); 7arr[ i ] = ptr->info; 8i++; 9InOrder2( ptr->right, arr, i ); 10} 11 } If the BST contains only one node, does InOrder2 work? Getting Elements In Order (cont.)

146 146 1 template 2 void BinarySearchTree::InOrder2( 3 BSTNode *ptr, Array & arr, int & i ) 4 { 5if ( ptr != NULL ) { 6InOrder2( ptr->left, arr, i ); 7arr[ i ] = ptr->info; 8i++; 9InOrder2( ptr->right, arr, i ); 10} 11 } In this case, the root node is the only node – the left and right pointers of the root node will be set to NULL. Getting Elements In Order (cont.)

147 147 1 template 2 void BinarySearchTree::InOrder2( 3 BSTNode *ptr, Array & arr, int & i ) 4 { 5if ( ptr != NULL ) { 6InOrder2( ptr->left, arr, i ); 7arr[ i ] = ptr->info; 8i++; 9InOrder2( ptr->right, arr, i ); 10} 11 } Getting Elements In Order (cont.)

148 148 1 template 2 void BinarySearchTree::InOrder2( 3 BSTNode *ptr, Array & arr, int & i ) 4 { 5if ( ptr != NULL ) { 6InOrder2( ptr->left, arr, i ); 7arr[ i ] = ptr->info; 8i++; 9InOrder2( ptr->right, arr, i ); 10} 11 } ptr->left is NULL, so NULL is passed into ptr of the new InOrder2 function that is made Getting Elements In Order (cont.)

149 149 1 template 2 void BinarySearchTree::InOrder2( 3 BSTNode *ptr, Array & arr, int & i ) 4 { 5if ( ptr != NULL ) { 6InOrder2( ptr->left, arr, i ); 7arr[ i ] = ptr->info; 8i++; 9InOrder2( ptr->right, arr, i ); 10} 11 } Since ptr is NULL in the new InOrder2 function, it will return right away Getting Elements In Order (cont.)

150 150 1 template 2 void BinarySearchTree::InOrder2( 3 BSTNode *ptr, Array & arr, int & i ) 4 { 5if ( ptr != NULL ) { 6InOrder2( ptr->left, arr, i ); 7arr[ i ] = ptr->info; 8i++; 9InOrder2( ptr->right, arr, i ); 10} 11 } Getting Elements In Order (cont.)

151 151 1 template 2 void BinarySearchTree::InOrder2( 3 BSTNode *ptr, Array & arr, int & i ) 4 { 5if ( ptr != NULL ) { 6InOrder2( ptr->left, arr, i ); 7arr[ i ] = ptr->info; 8i++; 9InOrder2( ptr->right, arr, i ); 10} 11 } i is still 0 from the driver – ptr is the root at this level – so the info at the root is placed into arr[ 0 ] Getting Elements In Order (cont.)

152 152 1 template 2 void BinarySearchTree::InOrder2( 3 BSTNode *ptr, Array & arr, int & i ) 4 { 5if ( ptr != NULL ) { 6InOrder2( ptr->left, arr, i ); 7arr[ i ] = ptr->info; 8i++; 9InOrder2( ptr->right, arr, i ); 10} 11 } i becomes 1 Getting Elements In Order (cont.)

153 153 1 template 2 void BinarySearchTree::InOrder2( 3 BSTNode *ptr, Array & arr, int & i ) 4 { 5if ( ptr != NULL ) { 6InOrder2( ptr->left, arr, i ); 7arr[ i ] = ptr->info; 8i++; 9InOrder2( ptr->right, arr, i ); 10} 11 } ptr->right is NULL – thus, the recursive function call immediately returns as before Getting Elements In Order (cont.)

154 154 1 template 2 void BinarySearchTree::InOrder2( 3 BSTNode *ptr, Array & arr, int & i ) 4 { 5if ( ptr != NULL ) { 6InOrder2( ptr->left, arr, i ); 7arr[ i ] = ptr->info; 8i++; 9InOrder2( ptr->right, arr, i ); 10} 11 } InOrder2 returns back to the driver with the correct array Getting Elements In Order (cont.)

155 155 1 template 2 void BinarySearchTree::InOrder2( 3 BSTNode *ptr, Array & arr, int & i ) 4 { 5if ( ptr != NULL ) { 6InOrder2( ptr->left, arr, i ); 7arr[ i ] = ptr->info; 8i++; 9InOrder2( ptr->right, arr, i ); 10} 11 } InOrder2 works correctly when there is only one node Getting Elements In Order (cont.)

156 156 1 template 2 void BinarySearchTree::InOrder2( 3 BSTNode *ptr, Array & arr, int & i ) 4 { 5if ( ptr != NULL ) { 6InOrder2( ptr->left, arr, i ); 7arr[ i ] = ptr->info; 8i++; 9InOrder2( ptr->right, arr, i ); 10} 11 } So InOrder2 works correctly when there is only one node in the BST or the BST is empty (root is NULL) Getting Elements In Order (cont.)

157 157 1 template 2 void BinarySearchTree::InOrder2( 3 BSTNode *ptr, Array & arr, int & i ) 4 { 5if ( ptr != NULL ) { 6InOrder2( ptr->left, arr, i ); 7arr[ i ] = ptr->info; 8i++; 9InOrder2( ptr->right, arr, i ); 10} 11 } Thus, it will work for a larger tree with 0 or 1 nodes in the left subtree, and 0 or 1 nodes in the right subtree, etc., etc. Getting Elements In Order (cont.)

158 158 1 template 2 void BinarySearchTree::InOrder2( 3 BSTNode *ptr, Array & arr, int & i ) 4 { 5if ( ptr != NULL ) { 6InOrder2( ptr->left, arr, i ); 7arr[ i ] = ptr->info; 8i++; 9InOrder2( ptr->right, arr, i ); 10} 11 } Consider the general case: p nodes in the left subtree and r nodes in the right subtree Getting Elements In Order (cont.)

159 159 1 template 2 void BinarySearchTree::InOrder2( 3 BSTNode *ptr, Array & arr, int & i ) 4 { 5if ( ptr != NULL ) { 6InOrder2( ptr->left, arr, i ); 7arr[ i ] = ptr->info; 8i++; 9InOrder2( ptr->right, arr, i ); 10} 11 } We assume that InOrder2 does what it is supposed to do Getting Elements In Order (cont.)

160 160 1 template 2 void BinarySearchTree::InOrder2( 3 BSTNode *ptr, Array & arr, int & i ) 4 { 5if ( ptr != NULL ) { 6InOrder2( ptr->left, arr, i ); 7arr[ i ] = ptr->info; 8i++; 9InOrder2( ptr->right, arr, i ); 10} 11 } The p nodes in the left subtree are all less than the root node, and will occupy the first p positions of the array. Getting Elements In Order (cont.)

161 161 1 template 2 void BinarySearchTree::InOrder2( 3 BSTNode *ptr, Array & arr, int & i ) 4 { 5if ( ptr != NULL ) { 6InOrder2( ptr->left, arr, i ); 7arr[ i ] = ptr->info; 8i++; 9InOrder2( ptr->right, arr, i ); 10} 11 } i is always incremented after adding an element, so… Getting Elements In Order (cont.)

162 162 1 template 2 void BinarySearchTree::InOrder2( 3 BSTNode *ptr, Array & arr, int & i ) 4 { 5if ( ptr != NULL ) { 6InOrder2( ptr->left, arr, i ); 7arr[ i ] = ptr->info; 8i++; 9InOrder2( ptr->right, arr, i ); 10} 11 } The root writes its info correctly in position p + 1 of the array Getting Elements In Order (cont.)

163 163 1 template 2 void BinarySearchTree::InOrder2( 3 BSTNode *ptr, Array & arr, int & i ) 4 { 5if ( ptr != NULL ) { 6InOrder2( ptr->left, arr, i ); 7arr[ i ] = ptr->info; 8i++; 9InOrder2( ptr->right, arr, i ); 10} 11 } Then, the last r nodes of the right subtree (all greater than the root) are written in the last r positions of the array Getting Elements In Order (cont.)

164 164 1 template 2 void BinarySearchTree::InOrder2( 3 BSTNode *ptr, Array & arr, int & i ) 4 { 5if ( ptr != NULL ) { 6InOrder2( ptr->left, arr, i ); 7arr[ i ] = ptr->info; 8i++; 9InOrder2( ptr->right, arr, i ); 10} 11 } Again, we assume InOrder2 does what it is supposed to do Getting Elements In Order (cont.)

165 165 1 template 2 void BinarySearchTree::InOrder2( 3 BSTNode *ptr, Array & arr, int & i ) 4 { 5if ( ptr != NULL ) { 6InOrder2( ptr->left, arr, i ); 7arr[ i ] = ptr->info; 8i++; 9InOrder2( ptr->right, arr, i ); 10} 11 } Thus, if we assume the recursive call of InOrder2 does what it is supposed to do, we have established the correctness… Getting Elements In Order (cont.)

166 166 1 template 2 void BinarySearchTree::InOrder2( 3 BSTNode *ptr, Array & arr, int & i ) 4 { 5if ( ptr != NULL ) { 6InOrder2( ptr->left, arr, i ); 7arr[ i ] = ptr->info; 8i++; 9InOrder2( ptr->right, arr, i ); 10} 11 } since InOrder2 works with smaller cases, we build larger cases from the smaller cases, using the smaller cases as left and right subtrees Getting Elements In Order (cont.)

167 167 1 template 2 void BinarySearchTree::InOrder2( 3 BSTNode *ptr, Array & arr, int & i ) 4 { 5if ( ptr != NULL ) { 6InOrder2( ptr->left, arr, i ); 7arr[ i ] = ptr->info; 8i++; 9InOrder2( ptr->right, arr, i ); 10} 11 } How do we know the time complexity is  ( n )? Getting Elements In Order (cont.)

168 168 1 template 2 void BinarySearchTree::InOrder2( 3 BSTNode *ptr, Array & arr, int & i ) 4 { 5if ( ptr != NULL ) { 6InOrder2( ptr->left, arr, i ); 7arr[ i ] = ptr->info; 8i++; 9InOrder2( ptr->right, arr, i ); 10} 11 } InOrder2 is called once from the driver. Then, for each node in the tree, 2 calls to InOrder2 are made, giving us a total of 2n + 1 calls. Getting Elements In Order (cont.)

169 169 1 template 2 void BinarySearchTree::InOrder2( 3 BSTNode *ptr, Array & arr, int & i ) 4 { 5if ( ptr != NULL ) { 6InOrder2( ptr->left, arr, i ); 7arr[ i ] = ptr->info; 8i++; 9InOrder2( ptr->right, arr, i ); 10} 11 } Since InOrder2 is called a total of 2n + 1 times, it is  ( n ) Getting Elements In Order (cont.)

170 170 Ensuring a Balanced BST Various schemes have been used to ensure a BST is balanced –red-black trees –AVL trees Insertion, searching, and deletion are all guaranteed to be O( lg n ), using the tightest big-oh notation

171 171 Ensuring a Balanced BST (cont.) The BST is faster, on average, than the red-black / AVL trees –BST’s are usually balanced –more work is required to ensure balancing However, the red-black / AVL trees give consistent performance –faster when BST’s are unbalanced –important in time-critical applications

172 172 Comparison of BST to Doubly-Linked List The hash table implementation of a doubly-linked list can be an alternative –under uniform hashing, a search can be done in  ( 1 ) time –an insertion is done in  ( 1 ) time (inserting at the head of the list) –under uniform hashing, a deletion is done in  ( 1 ) time –what about providing elements in order?

173 173 Comparison of BST to Doubly-Linked List (cont.) A linked list can be sorted without affecting the time complexity of the sorting algorithm (as in the previous chapter) It generally takes  ( n lg n ) time to sort a linked list It is possible to sort in  ( n ) time (under favorable conditions) Once sorted, the elements can be provided in order

174 174 Since BST’s are usually balanced, it generally takes about  ( n lg n ) time to insert n elements into a BST It takes  ( n ) time to insert n elements at the head of a doubly-linked list The one to select, BST or doubly-linked list, depends on the situation one is working with (as usual) Comparison of BST to Doubly-Linked List (cont.)

175 175 Graphs Graphs are a very general data structure A graph consists of a set of nodes called vertices Any vertex can point to any number of other vertices It is possible that no vertex in the graph points to any other vertex Each vertex may point to every other vertex, even if there are thousands of vertices

176 176 A Directed Graph (Digraph) A D B C E F Each pointer is called an edge

177 177 An Undirected Graph A D B C E F Each edge points in both directions – ex: A points to D and D points to A

178 178 Another Digraph A D B C E F Nodes A and F point to each other – it is considered improper to draw a single undirected edge between them

179 179 Weighted Graph Graphville Node Town Vertex City Pointerburgh Builder’s Paradise Binary Tree Valley 3 8 4 4 10 4 2

180 180 Graph Implementation A vertex A is said to be adjacent to a vertex B if there is an edge pointing from A to B Graphs can be implemented in a couple of popular ways: –adjacency matrix –adjacency list

181 181 Adjacency Matrix Nodes are given a key from 0 to n – 1 The adjacency matrix is a 2-dimensional array of bool type variables

182 182 F T T F F T F F T T T F F F F T F F F T F T T T F F F F F T 012345012345 Adjacency Matrix (cont.) 0 1 2 3 4 5 T T F F F F

183 183 F T T F F T F F T T T F F F F T F F F T F T T T F F F F F T 012345012345 Adjacency Matrix (cont.) 0 1 2 3 4 5 T T F F F F The row numbers give the vertex number of the vertex that an edge is pointing from

184 184 F T T F F T F F T T T F F F F T F F F T F T T T F F F F F T 012345012345 Adjacency Matrix (cont.) 0 1 2 3 4 5 T T F F F F Example: Node 1 points to Node 2 (set to T)

185 185 F T T F F T F F T T T F F F F T F F F T F T T T F F F F F T 012345012345 Adjacency Matrix (cont.) 0 1 2 3 4 5 T T F F F F Example: But Node 2 doesn’t point to Node 1 (set to F)

186 186 F T T F F T F F T T T F F F F T F F F T F T T T F F F F F T 012345012345 Adjacency Matrix (cont.) 0 1 2 3 4 5 T T F F F F Note that we can construct a graph from the adjacency matrix – the vertices may not be drawn in the same locations as the original graph, but the connections will be the same

187 187 Adjacency List An adjacency list is an array of linked lists The vertices are numbered 0 through n – 1 Each index in the array corresponds to the number of a vertex The vertex (with an index number) is adjacent to every node in the linked list at that index

188 188 Adjacency List (cont.) 1 2 5 4 3 5 1 3 012345012345

189 189 Adjacency List (cont.) 1 2 5 4 3 5 1 3 012345012345 Vertex 1 is adjacent to vertex 2, and vertex 1 is also adjacent to vertex 5

190 190 Adjacency List (cont.) 1 2 5 4 3 5 1 3 012345012345 Note: vertex 2 may not connect to vertex 5 in the graph: 1 2 5

191 191 Adjacency List (cont.) 1 2 5 4 3 5 1 3 012345012345 Vertex 3 has an empty linked list – it is not adjacent to any other vertices

192 192 Adjacency List for Weighted Graph 1 3 012345012345 2 4 3 8 0 3 3 4 0 4 4 4 5 10 0 8 1 4 5 2 2 4 2 10 3 2 Red font is for vertex numbers, black font is for weights

193 193 Vertex Info Ordinarily, the vertex info is not stored in a linked list node of an adjacency list The vertex info size may be huge, and many duplicates of it would be stored throughout the adjacency list, wasting space Instead, a separate array contains the vertex info objects; each index corresponds to a vertex number for easy look-up

194 194 Adjacency Matrix vs. Adjacency List The speed of the adjacency matrix or the adjacency list depends on the algorithm –some algorithms need to know if there is a direct connection between two specific vertices – the adjacency matrix would be faster –some algorithms are written to process the linked list of an adjacency list, node by node – the adjacency list would be faster

195 195 Adjacency Matrix vs. Adjacency List (cont.) When both seem equally fast for a certain algorithm, then we consider memory usage We will consider the space complexity of each implementation Space complexities are like time complexities, but they tell us the effects on memory space usage as the problem size is varied

196 196 An array of vertex info is used for each implementation, which is  ( n ) In the adjacency matrix, each dimension is n, so the spatial complexity is  ( n 2 ) In the adjacency list, there are n elements in the array, giving a spatial complexity of  ( n ) for the array Adjacency Matrix vs. Adjacency List (cont.)

197 197 Note that each edge corresponds to a linked list node in the adjacency list There can be no more than n( n – 1 ) edges in a graph, so the spatial complexity for the linked list nodes is O( n 2 ) the total spatial complexity for the adjacency list is O( n 2 ) Adjacency Matrix vs. Adjacency List (cont.)

198 198 Both of the spatial complexities for the adjacency matrix and the adjacency list absorb the  ( n ) spatial complexity used in the vertex info array The spatial complexity of the adjacency list really depends on whether the graph is sparse or dense Adjacency Matrix vs. Adjacency List (cont.)

199 199 A sparse graph does not have that many edges relative to the number of vertices – if the number of edges is less than or equal to n, then the spacial complexity of the adjacency list is  ( n ) In a dense graph, there may be close to n 2 edges, and then the spatial complexity of the adjacency list is  ( n 2 ), the same as that for the adjacency matrix Adjacency Matrix vs. Adjacency List (cont.)


Download ppt "1 C++ Classes and Data Structures Jeffrey S. Childs Chapter 15 Other Data Structures Jeffrey S. Childs Clarion University of PA © 2008, Prentice Hall."

Similar presentations


Ads by Google