CS 315 Data Structures mid-term 2 1) Shown below is an AVL tree T. Nov 14, 2012 Solutions to OPEN BOOK section. (a) Suggest a key whose insertion does not require any rotation. 18 (b) Suggest a key, if it exists, whose insertion requires a single rotation. 45 (c) Suggest a key, if it exists, whose insertion requires a double rotation. 50 (d) Given that the last operation was inserting the key 48 and that this insertion involved a rotation, exhibit the tree prior to inserting 48. One solution is as follows: (e) Exhibit that the AVL tree that results from inserting 39 into T.
2) (a) Suggest a data structure that can support the operations INSERT and FINDMIN with worstcase O(1) cost per operation. Your solution should include the description of the data members of the class that supports the operations (illustrated with a diagram), and actual code to implement INSERT and FINDMIN operations. FINDMIN will return the smallest key currently stored, but will not remove it. (Note: there is a simple solution to this problem.) Informal outline: Use an unsorted array KEYS to keep the keys inserted. Insertion can be done in O(1) time by simply adding the new key to the end of the array. A data member LastPtr will point to the last member of the array. In addition, keep a variable MinPtr that holds the index of the min key. This will allow us to perform FINDMIN in O(1) time. But this will require a small change to INSERT. Compare the new key with the current min and update MinPtr if needed. Code for INSERT and FINDMIN: void INSERT(<comparable> x) { KEYS[++LastPtr] = x; if (x < KEYS[MinPtr]) MinPtr = LastPtr; <comparable> FINDMIN() { return KEYS[MinPtr];
(b) Suggest a simple modification to a standard data structure studied in class to support the operations SEARCH, INSERT and DELETE in O(log n) time in the worst-case, and FINDMIN in O(1) time in the worst-case. You don t have to write any code for this problem. Describe the changes you would make to a standard data structure informally and explain how this would meet the performance goals. Since the set of operations we want to support includes all the dictionary operations and we require worst-case O(log n) performance, the only choice we have is to use AVL tree. But using AVL tree directly will not give us O(1) bound for FINDMIN. So we need to add an extra data member - a pointer to the node containing the minimum key. (Tree* MinPtr) This will immediately allow us to implement FINDMIN in O(1) time. (Simply return MinPtr->key will do it.) However, this will require us to modify the code for insert and delete. A simple way to do this is as follows: after every INSERT or DELETE operation, start at the root of the tree and follow a chain of left links until you reach a node with no left child. Reset MinPtr to point to this node. Note that this additional cost is within acceptable bound for Insert and Delete operations. 3) When assigned to write a function checkbst to test if a given binary tree is a binary search tree, a student wrote the following program. (The binary tree has the usual fields key, left and right.) bool checkbst(tree* T) { // test if T points to a binary search tree if (T == NULL) return true; if!(checkbst(t->left)) return false; if!(checkbst(t->right)) return false; if (T->left!= NULL) && (T->left->key > T->key)) return false; if (T->right!= NULL) && (T->right->key < T->key) return false;
return true; (a) If it exists, exhibit a binary tree that is not a binary search tree for which the above program will produce a correct output. We want a non-bst that is correctly classified by the above function as a non- BST. One such tree is (b) If it exists, exhibit a binary tree that is not a binary search tree for which the above program will produce a wrong output. We want a non-bst that is incorrectly classified by the above function as a BST. One such tree is: (c) If it exists, exhibit a binary tree that is a binary search tree for which the above program will produce a wrong output. We want a BST that is incorrectly classified by the above function as a BST. Such tree does not exist since all the conditions tested by the above function are required to be satisfied by a BST. (d) If it exists, exhibit a binary tree that is a binary search tree for which the above program will produce a correct output. We want a BST that is correctly classified by the above function as a BST. One such tree is
4) Consider a binary search tree, in which in addition to the standard fields (key, left and right) each node has an integer field called size, which stores the number of elements in the subtree rooted at this node. In a range query we are given two key values x1 and x2 and wish to return a count of the number of elements in the tree whose key value x satisfies x1 < x <= x2. Write a function to implement this operation, and briefly explain how your algorithm works. Your code should closely resemble c++ and should run in O(h) time, where h is the height of the tree. Informal description of the algorithm: We write a helper function called CountLessThan that takes as input a tree pointer T and a key K, and returns the number of number of nodes in the tree that are < K. The range query can be answered by computing CountLessThan(x2) CountLessThan(x1), then adding 1 if x2 is in the tree. int range(tree* T, int x1, int x2) { return CountLessThan(T, x2) CountLessThan(T, x1)+ find(t, x2); Here we assume that find returns 0 or 1 depending on whether x2 is (is not) in the tree T. The function CountLessThan works as follows: it takes as input a tree pointer T and int K. If the root key x <= K, then we can recursively return CountLessThan(T->left, K). Else, x > K. Thus, all the keys in the left subtree together with the root key should be included in the count. Add to this, the value returned by the recursive call CountLessThan(T->right, K). Note that the number of times the call is made is O(h) and after each call, a constant number of additional operations are performed thus the total cost is O(h):
5) int CountLessThan(Tree* T, int K) { if (T== NULL) return 0; if (T->key <= K) return CountLessThn(T->left, K); else { int temp; if (T->left == NULL) temp = 0; else temp = T->left->size; return 1 + temp + CountLessThan(T->right, K); Here h(x) denotes the primary hash function and g(x) denotes the secondary hash function. (a) 2, 3, 4 (b) 2, 3, 6, 1 (c) 2, 9, 6, 3, 0 The last index is the position in which the key is inserted.