CS140 Midterm 2 Answers

Fall 2009

  1. (20 points)
     
         a. array
         b. singly-linked list
         c. doubly-linked list
         d. linked-list queue
         e. circular, array queue
         f. stack
    

    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. array The most space-efficient data structure you could use to implement a stack in which there is an upper limit, max, on the number of elements that can be stored on the stack.
    2. singly-linked list The most space-efficient data structure you could use to implement a stack in which the the number of elements that can be stored on the stack is unlimited.
    3. array The data structure which allows any of its elements to be accessed in constant time.
    4. doubly-linked list The data structure you would use if you needed to be able to delete an element in the middle of the data structure.
    5. stack The data structure you would use to ensure that the last item added to the data structure is always the first item removed from the data structure.
    6. circular, array queue The most space-efficient data structure you could use if you wanted to print out the last n lines of a file where n is a command-line argument.
    7. stack The data structure you would use to check whether a set of parentheses were balanced in an expression.
    8. linked-list queue The data structure you would use if you wanted to simulate an unbounded line of customers at a grocery store, where customers are served from the front of the line and customers enter at the back of the line.
    9. doubly-linked list The data structure that allows you to traverse its elements in either forward or reverse order.
    10. circular, array queue The data structure that you could use to implement streaming video on a video card with a fixed amount of memory.

  2. (16 points) Suppose I want to write a library package for a vector. A vector is an array that can be dynamically resized if it is not big enough. The library would worry about calling realloc so the user does not have to. I want to use information hiding to implement the vector library. My implementation will have two files named vector.h and vector.c. Answer the following questions:

    1. I want to provide a function called new_vector that is passed the initial vector size as an integer parameter. Write the function declaration for new_vector (do not write the definition, just the declaration as it would appear in the .h file). I have intentionally not told you what the return value is. You should be able to figure it out based on the fact that I want you to use information hiding.

      void *new_vector(int size);

    2. void *: I want my vector to be able to store generic data. What should be the type of the value that it stores. For example, if I have the function description:

      void vector_set(? vector, int index, ? value): Sets the entry at the specified index to value.

      what should be the declared type of value? That is what should the ? before value be replaced by? (Please do not tell me the type of vector--the question mark before vector is there because I do not want to give away the answer to question a).

    3. Where should the structs for the vector's implementation be declared. Put a check mark next to the appropriate answer:

      1. __________ vector.h

      2. xxxxxxxxxx vector.c

      3. __________ the user's .c file
    4. Declare a struct for the vector's container object. Use a typedef to name the struct "vector". You need to figure out what fields the struct needs and then declare them. Hint: The container object will need to have a pointer to something that holds the vector's data, it will need to keep track of its capacity and it will need to be able to figure out when it must resize itself.
      
           typedef struct {
             void **data;
             int capacity;
             int size;
           } vector;
      
  3. (12 points) You have a circular queue with a capacity of 8 elements. For each of the following two subparts, show what the contents of the array will be after the specified sequence of enqueue and dequeue operations, and show where the front and back indices will point. If an array entry is empty, either because it has never been filled, or because its value has been dequeued, then leave its box blank.
    1. enqueue(6);
      enqueue(5);
      enqueue(3);
      enqueue(2);
      dequeue();
      dequeue();
      
         0     1     2     3     4     5     6     7   
      -------------------------------------------------
      |     |     |     |     |     |     |     |     |
      |     |     |  3  |  2  |     |     |     |     |
      -------------------------------------------------
                     ^     ^
                   front  back
      
    2. Now you receive the following additional set of enqeueue and dequeue operations. Show the contents of the array and where the front and back pointers point after these additional operations have been applied to the queue (i.e., do not start from scratch but build on the queue that you started in the previous part).
      enqueue(7);
      enqueue(8);
      enqueue(2);
      enqueue(11);
      dequeue();
      dequeue();
      enqueue(9);
      
         0     1     2     3     4     5     6     7   
      -------------------------------------------------
      |     |     |     |     |     |     |     |     |
      |  9  |     |     |     |  7  |  8  |  2  | 11  |
      -------------------------------------------------
         ^                       ^
       back                    front
        
  4. (16 points) Consider the following declarations and function: push(int i, Stack *s); // push an integer i onto s int pop(Stack *s); // pop an integer off s and return its value bool isEmpty(Stack *s); // return true if the s is empty and false otherwise int mystery(Stack *stack) { char token; int count = 0; int x; while (scanf("%c", &token) != EOF) { if (token == '{') { count++; push(count, stack); } else if (token == '}') { if (isEmpty(stack)) return 0; else x = pop(stack); } // any token other than a { or a } is ignored } if (isEmpty(stack)) { return -1; } else return pop(stack); } Suppose the input is:
    { hi { brad { how } { are } { you
    
    1. What is the contents of stack after the second } is read? Some of your entries may be empty. Fill the stack from bottom to top:
           ______________
           |            |
           |            |
           --------------
           |            |
           |            |
           --------------
           |            |
           |            |
           --------------
           |            |
           |     2      |
           --------------
           |            |
           |     1      |
           --------------
      
      
    2. Given this input, what does mystery return? 5

    3. mystery is checking something. What is it checking for?

      It is checking to see whether or not the curly braces are balanced .

    4. mystery returns three different values--0, -1, or x--depending on the outcome of its check. How would your calling program interpret each of these return values? That is, if your program had to print a message explaining the meaning of the return value, what would it say. Be concise (you may want to defer this question to the end of the test because you might have to devise a couple sample input sequences to figure it out and that could take some time).

      1. 0: unmatched right brace
      2. -1: braces are matched
      3. x: number of the first unmatched left brace

  5. (16 points) Behold the following struct, which contains a union:
    struct account {
        int type;
        char name[30];
        double balance;
        union {
    	struct {
    	    int check_num;
    	    char *checks;
    	} checking;
    	struct {
    	    double interest_rate;
    	    double quarterly_interest;
    	    double annual_interest;
    	} savings;
        } acct_info;
    };
    
    1. 24: How many bytes will be allocated to just the union field (i.e., acct_info)? You should make the following assumptions:

      • ints and pointers are 4 bytes
      • doubles are 8 bytes
      • a single char takes 1 byte
      • fields are packed together as tightly as possible and word alignment is ignored.

    2. 66: How many bytes will be allocated to the entire struct (i.e., the account struct)?

    3. Suppose I have the declaration:
      struct account y;
      
      Write expressions to:

      1. copy the string "bvz" to the name field.

        strcpy(y.name, "bvz");

      2. assign 30 to the check_num field of checking.

        y.checking.check_num = 30;

      3. copy the string "Smiley" to the checks field of checking.

        y.checking.checks = strdup("Smiley");

      4. assign .05 to the annual_interest field.

        y.savings.annual_interest = .05;

  6. (20 points) You are given a singly linked list, L, of integers and an array P, containing integer indices sorted in ascending order. The function createList(L, P, Psize) will create and return a new list that contains the elements in L that correspond to the positions specified by P. For instance, if P = 1, 3, 4, 6, and L is the list:
    L -> 6 -> 20 -> 8 -> 25 -> 30 -> 41 -> 66 -> 10 -> 20
    
    then your new list will be:
    new_list -> 20 -> 25 -> 30 -> 66
    
    which, using zero-based indexing, correspond to the elements at index locations 1, 3, 4, and 6 in L. Write the procedure createElements(L,P,Psize) using my sllist library. In case you have forgotten, I have attached the interface for the sllist library to the end of the exam.

    Here is some helpful information:

    1. L is a pointer to an Sllist.
    2. P is a pointer to an integer array.
    3. Psize is the size of the integer array.
    4. The return value is a pointer to an Sllist.
    5. You may assume that P does not have integer indices that are larger than the number of elements in L. Hence you do not need to check whether you have run past the end of L.
    6. For maximum points, you should take advantage of the fact that P is in ascending order and traverse L only once. If you cannot figure out how to do this, you can traverse L multiple times for 16 points.
    7. You need to show me your function declaration and definition. Do not show me include files, statements to read data, etc. L and P have been prepared for you by the calling function.


Sllist *createList(Sllist *L, int *P, int Psize) {
  Sllist_Node *n;
  Sllist *new_list;
  int i, j;
  j = 0;
  new_list = new_sllist();
  n = sll_first(L);
  // iterate through the elements of P. Since we know that the elements
  // of P are in ascending order, we can traverse forward from the node 
  // that we are currently at in L to the next node specified by P.
  // I used a secondary index, j, that is incremented until it has reached 
  // the appropriate node in L, and then I add that node to the new list
  // that I am creating.
  for (i = 0; i < Psize; i++) {
    while (j < P[i]) {
      n = sll_next(n);
      j++;
    }
    sll_append(new_list, sll_val(n));
  }
  return new_list;
}

Sllist Library