CS302 -- Lab 5 -- Algorithm Analysis


Lab Objective

This lab is designed to give you experience with thinking about how to solve a problem in the most efficient way possible. For this lab you will not have to turn in programs. Instead you will submit a file in either plain text or pdf format that contains your solutions. (Note: we must require that your file be a plain text file or a pdf file, for the purposes of standardizing the grading process.)


Problems

  1. (20 points) Write a routine to list out the nodes of a binary tree in level-order. List the root, then nodes at depth 1, followed by nodes at depth 2, and so on. Each node should be prefixed by its level number. For example, given the tree:
                                     10
                                    /  \
                                   /    \
                                   5    15
                                  /       \
                                 /         \
                                 3         20
                                             \
                                             25
                                            /
                                           22
    
    your routine should print:
       0        10
       1        5
       1        15
       2        3
       2        20
       3        25
       4        22
    
    For full credit your routine must run in linear time (i.e., O(n), where n is the number of nodes in the tree). Assume you have the class definition:
       class treenode {
          public:
    	int value;
            treenode *left_child;
            treenode *right_child;
       };
    

    1. Hint: You will not be able to use recursion for your solution.
    2. You may write pseudo-code for this problem (i.e, your answer does not have to be implemented C++ code.) All we are interested in seeing is a function that takes a pointer to a node as an argument. For example:
      	void print_levels(treenode *root)
      	
    3. You may assume that the left_child pointer will be 0 if a node does not have a left child; similarly, you may make the same assumption for right_child.
    4. If you want to test your solution there is program called printLevels.cpp found in /home/parker/courses/cs302/labs/lab5/. It has a comment that shows you where you should insert your code. You can invoke the test program by typing:
      	printLevels seed child_probability max_depth
      	
      seed is a seed for the random number generator that will be used to generate children and values for the children. child_probability gives the probability that a left child or right child will exist. It must be a real number between 0 and 1. max_depth is the maximum depth of the tree. Without max_depth the tree generator routine may get into an infinite recursion because it will keep trying to generate children.

      The test program first prints out the generated tree and then calls your print levels function. The test program prints one node per line and indents each level by two spaces. For example, the above tree would be printed as:

      	10
      	  5
      	    3
      	      ----
         	      ----
      	    ----
      	  15
      	    ----
      	    20
      	      ----
      	      25
      	        22
      	          ----
                        ----
                    ----
      	

  2. (20 points) Write a function that takes two integer arguments and returns their product using only addition and bit shifts. A bit shift is written as either "var = var << n" or "var = var >> n". The << operator left shifts the bits in var by n bits and fills in the opened positions with 0's. It corresponds to multiplying the number by 2n. For example, 10 is represented internally by the bit string 1010. If we left shift 10 by 2 bits we obtain 101000 which you can verify is 10 * 22 or 40. The >> operator right shifts the bits in var by n bits. The low order n bits are thrown away and the high order bits are replaced by 0's. This corresponds to dividing a number by 2n. For example, right shifting 1010 by one bit results in the string 0101 or 5. For this problem you will need to use both the left shift and right shift operators. The obvious algorithm for doing multiplication using only addition is:
    	int multiply(int factor1, int factor2) {
    	    int multiplier = (factor1 < factor2) ? factor1 : factor2;
     	    int multiplicand = (factor1 > factor2) ? factor1 : factor2:
    	    int product = 0;
    	    for (int i = 0; i < multiplier; i++)
    		product += multiplicand;
    	    return product;
     	}
    	
    This algorithm runs in O(min(factor1, factor2)), which is a linear time algorithm. You can obtain an O(min(log factor1, log factor2)) algorithm if you use addition and bit shifts. Write such an algorithm using C-code.

    Hints

    1. C++ has a bitwise & operator that will do a bit-wise 'and' of two integers. For example:
      	     a = 14;
      	     b = 3;
      	     a & b = (1110 & 0011) = 0010 = 2
      	     
      Bit-wise 'and' can prove helpful for inspecting the bits of an integer. In the above example 3 was used to extract the first two bits of 14.

  3. (10 points) Insertion code in a heap can be simplified by placing a sentinel value in array location 0 (see discussion of this on page 216 of Weiss). For example, if we knew that -1 would always be less than any value that would be inserted into the heap, we could make -1 the sentinel value. In general we do not know the minimum value that will be inserted into the heap. What value can we use as a sentinel value in that case? Hint: you may need to use a different sentinel value for each insertion.

  4. (10 points) The graphs below show the results of programs that perform search on various sets of random and ordered data. The search techniques include linear search, red black trees, binary search trees, and hash tables. The "insert" graphs show the total time to insert n elements for different values of n. The "find" (or "search") graphs show the total time to perform n successful searches and n unsuccessful searches (2n total searches) for specified values of n.

    Answer each of the following questions and explain why you answered it the way you did.

  5. (20 points) Work Exercise 2.27 in the Weiss text. If you want to write a C++ function to test your solution you can paste it into the testMatrix.cpp program found in /home/parker/courses/cs302/labs/lab5/. You can invoke the test program by typing:
    	matrix n seed
    	
    where seed is a seed for the random number generator that creates entries in the matrix.

    Hints

    1. You may find it helpful to allocate an (N+2)X(N+2) matrix and use sentinel values.
    2. It is possible to determine whether or not a number is in the matrix with no more than 4N comparisons.
    3. Any O(N) solution is adequate; don't worry if your solution uses more than the minimum.
    4. You cannot determine whether or not a number is in the matrix using a single pass that crawls forward through the matrix. You may have to move both forward and backwards.
    Extra Credit (5 points)

    The integer function int sign(int) returns

    Give a solution that uses 2N calls to the sign function, no comparisons, and places a minimum number of sentinel values. Hint: You may use the C++ switch statement.


What to Hand In

Submit an ascii text file or pdf file named lab5-solutions. Do not submit an MS Word (or any other format) document.