CS140 Final

Spring 2018

Instructions

  1. This paper exam has 8 problems worth 90 points and and the coding portion was worth 60 points, for a total of 150 points. You will be graded out of 150 points, so if your total combined score is 135, you will receive a 90 for the exam.

  2. Write your answers on the exam.

  3. Ensure that you write clearly and legibly. Failure to do so may result in the deduction of points.

  4. No electronic devices are allowed and all electronic devices that you have with you must be turned off, including calculators.

  5. You may not use any notes for this exam.

  6. Good luck!

  1. (10 points) Show the binary search tree that results if 200 is deleted from the tree below:
                               ---400---
                              /         \
                           -200-        500
                          /     \      /   \
                        150     325  450   600
                       /   \       \  	      
                      50   170     375
                          /
                        160
    

  2. (9 points) Show the result of doing a single left rotation about the node 250. Do not worry if the rotation increases the height of the tree. All I care about is whether you know how to perform a rotation.
                                -300-
                               /     \
                             175	 400
                            /   \
    		      100   250
    		      /    /   \
    		     50	 200   275
    
  3. (12 points) 160 has just been inserted into the following AVL tree, causing it to violate the AVL condition:
                         --100--
                        /       \
                       40        200
                      /  \      /   \
                     20  60   150   400
                              /  \
                            125  175
    			     /
    			   160
    

  4. (10 points) The greatest common divisor (gcd) of two non-zero numbers is the largest positive integer that divides the numbers with a remainder of 0. For example, the gcd of 48 and 20 is 4, the gcd of 48 and 12 is 12, and the gcd of 12 and 12 is 12.

    Euclid's algorithm is a recursive algorithm for finding the gcd of two integers a and b that can be expressed as follows:

    1. If a equals b, then the gcd is a
    2. Otherwise the gcd evenly divides the positive difference between a and b (|a-b|), and the smaller of a and b. For example, for 48 and 20:

      • gcd(48, 20) reduces to finding the gcd of 28, the difference between 48 and 20, and 20, which is the smaller of 48 and 20. That is gcd(48, 20) = gcd(28, 20).
      • gcd(28, 20) reduces to finding the gcd of 8 (28-20) and 20 (lesser of 20 and 28). That is gcd(28,20) = gcd(8, 20).
      • gcd(8, 20) reduces to finding the gcd of 12 (20-8) and 8 (lesser of 8 and 20). That is gcd(8,20) = gcd(8, 12).
      • gcd(8, 12) reduces to finding the gcd of 4 (12-8) and 8 (lesser of 8 and 12). That is gcd(8,12) = gcd(8, 4).
      • gcd(8, 4) reduces to finding the gcd of 4 (8-4) and 4 (lesser of 4 and 8). Thus gcd(8, 4) = gcd(4, 4).
      • gcd(4, 4) is 4 because 4 equals 4.
    We want you to write the recursive definition for gcd(a,b). Do not use C++ code. We just want a mathematical definition. For example, for n!, the mathematical definition is:

    1. Write the base case for gcd(a,b).
      
      
      
      
      
      
      
      	    
    2. Write the recursive case(s) for gcd(a,b).
      
                  if a > b, gcd(a, b) = 
      
      
      
                  if a < b, gcd(a, b) = 
      
      
      	    

  5. (12 points) Behold the following 4 fragments of code:
    (a)
    int i, j;
    int sum = 0;
    for (i = 0; i < n; i++) 
        sum += i;
    for (j = 0; j < n/2; j++)
        sum *= j;
         
    (b)
    int search(vector<string>names, string target) {
        int high = names.size()-1, low = 0, mid;
        do {
           mid = (low + high) / 2;
           if (target == names[mid]) 
                return mid;
           else if (target < names[mid])
                high = mid - 1;
           else
                low = mid + 1;
        } while (low <= high);
        return -1;
    }
    
    
    
    (c)
     int a, b;
     cin >> a >> b;
     a = a * a + 1;
     b = 1000 * b + 3 * a;
     b = b % 11;
     a = a % 13;
     if (a < b)
         cout << a;
     else
         cout << b;
    
    (d)
    int i, j;
    int sum = 0;
    for (i = 0; i < n; i++) {
        for (j = 1; j < n; j *= 2) {
    	sum += a[i][j];
        }	    
    }
    cout << sum;
         

    For each fragment of code, please circle its Big-O running time:

    a      O(1)    O(log n)   O(n)   O(n log n)   O(n2)  O(n3)   O(2n)
    
    b      O(1)    O(log n)   O(n)   O(n log n)   O(n2)  O(n3)   O(2n)
    
    c      O(1)    O(log n)   O(n)   O(n log n)   O(n2)  O(n3)   O(2n)
    
    d      O(1)    O(log n)   O(n)   O(n log n)   O(n2)  O(n3)   O(2n)
    

  6. (12 points)
     
         a. array
         b. vector
         c. stack
         d. deque
         e. hash table
         f. list
         g. binary search tree
         h. AVL tree
    

    For each of the following questions choose the best answer from the above list. Assume that the size of an array is fixed once it is created, and that its size cannot be changed thereafter. Sometimes it may seem as though two or more choices would be equally good. In those cases think about the operations that the data structures support and choose the data structure whose operations are best suited for the problem. You may have to use the same answer for more than one question:

    1. ____________ The data structure you should use if you want to implement a map using a tree and you want the tree that will be balanced regardless of whether the keys are presented in random order or nearly sorted order.

    2. ____________ The data structure that provides the most efficient average-case methods for finding, inserting, and deleting keys as long as the keys do not have to be kept in sorted order.

    3. ____________ The data structure you should use if you want to implement a stack where you insert or delete elements only at the back of the data structure and the data structure can become arbitrarily large.

    4. ____________ The data structure you should use to store a set of printing jobs, where new printing jobs should be added to the back of the queue and jobs to be printed should be removed from the front of the queue.

    5. ____________ The data structure that is used to implement hashing with linear probing when the size of the data is not known in advance.

    6. _____________ The data structure you will use for the following histogram-like program. It is going to take as input a bunch of exam scores which are integers and it will count how many scores of each value there is. For example, consider the following exam scores:
                             ( 11, 58, 23, 23, 11, 16, 23 )
                             
      Our program will report that 2 students scored an 11, 1 student scored a 16, 3 students scored a 23, and 1 student scored a 58. Assume that you know in advance that the scores range in value from 0-100.

  7. (10 points) You are given the following B-tree of order 5. Show the new btree that results when 700 is inserted into it.

  8. (15 points) Write a C++ function named InsertBefore that inserts a new item into a doubly-linked list before the given node. The function prototype for InsertBefore is:
    	  Dnode *InsertBefore(string value, Dnode *node);
    	
    value is the string to be inserted into the doubly-linked list and it should be inserted before node. The return value should be a pointer to the newly created node for value. Here is the declaration for Dnode:
    class Dnode {
      public:
        string s;
        Dnode *flink;
        Dnode *blink;
    };
    
    Assume that the list has a sentinel node so you are always guaranteed to have a predecessor node.