CS140 -- Lab 8

This lab is designed to give you practice with using recursion.


Materials

You will need the following files:


Part 1--Basic Recursion

This part will be performed in class in conjunction with the lab lecture by the TA. To start this part, copy the file /home/bvz/cs140/labs/lab8/count.c to your home directory. Take a look at it. It's designed to take a command line argument and count down from that argument. Do the following things:

  1. Compile the file and execute it
  2. In the function count, remove the two lines that read:
      if (numberOfRepetitions == 0)
        return;
    
    These two lines constitute what is called the base case of the recursion. This concept will be described in greater detail in lab. What do you think will happen when count is now executed? Compile it, execute it, and see if your hypothesis is correct.

  3. Add back the previous two lines to count and now change the line:
      count(numberOfRepetitions-1);
    
    so that it reads:
      count(numberOfRepetitions);
    
    The first line causes count to make progress toward ending the recursion, but the second line does not. More about this will be said in the lab. What do you think will happen when count is now executed? Compile it, execute it, and see if your hypothesis is correct.

Part 2--Binary Search

You are going to write a recursive binary search function named binarySearch in this part. If you have never seen binary search, or do not remember it well, here is a description of it. binary search tries to locate a key in an array of data. It returns the index location of that key if it finds it, and -1 otherwise. binarySearch takes four arguments:

  1. an integer key to be located.
  2. an array of integer data to be searched. The data will be in ascending order and you may assume there are no duplicates.
  3. a beginning index at which to start searching.
  4. an ending index at which to stop searching.
Initially the beginning index will be 0 and the ending index will be 1 less than the size of the array. For example, if the array is named data and the array has 20 elements, the first call to binary search would look like:
binarySearch(key, data, 0, 19);
The search strategy is as follows:

  1. If end is less than begin, then key is not in the array, so return -1.
  2. Look at the middle item in the array, which is computed as the item at index location (begin+end)/2. If the key equals the element at this location, return the index location.
  3. If key is less than the element at the middle of the array, then the key must be in the left part of the array. Call binarySearch recursively on the left part of the array. You will need to make sure that the beginning and ending values that you pass to the recursive call are updated appropriately.
  4. Otherwise the key must be greater than the element at the middle of the array, so call binarySearch recursively on the right part of the array. You will need to make sure that the beginning and ending values that you pass to the recursive call are updated appropriately.
Place your function in a file named binarySearch.c. I have provided a test driver file named driver.c. Compile driver.c and binarySearch.c and link them into an executable named driver. Then trying running it with the following command:
driver numbers.txt
driver will prompt you for keys for which to search. If you look in numbers.txt you can see which numbers are in the data set (the first number in the file is the number of items in the data set). You should try testing your function with both keys that are in the data set and keys that are not in the data set.


Part 3 (Optional)--Quicksort (25 extra credit points)

Finish the quicksort function started in class by writing the code for partitioning the array into three parts: 1) the left part whose elements are less than the pivot, 2) the single element middle part which is the pivot, and 3) the right part whose elements are greater than the pivot. Place the quicksort function in a file named quicksort.c. Here is some information you may find helpful:

  1. You may assume that your data consists of integers and that all the integers are unique.
  2. The pivot is the first element in the array.
  3. There is a test driver file named qdriver.c that you can use to test your quicksort function. Compile quicksort.c and qdriver.c into an executable named qdriver and then try it out with the file named qsort_data.txt. The first line of qsort_data.txt gives the number of elements in the file and the remaining elements are the numbers to be sorted. An invocation would look like:
    qdriver qsort_data.txt
    
    You can try out your own files by creating files of integers and including the number of integers in the file as the first element of the file.
  4. The best way to do the partition is to start with two indices left and right. left should initially be set to begin+1, so that it points to the element immediately after the pivot element, and right should initially be set to end. You should then iteratively perform the following actions:

    1. Increment left until you encounter an element that is greater than the pivot. This element should be swapped to the right part of the array.
    2. Decrement right until you encounter an element that is less than the pivot. This element should be swapped to the left part of the array.
    3. If left is still less than right, then swap the two elements to which they point.
    4. At some point the left and right pointers will cross and lie next to each other, with right being 1 less than left. At this point you can swap the pivot element with the element to which right points, since right points to an element less than the pivot (or in the worst case, right points to the pivot, in which case the pivot gets swapped with itself). This will cause the pivot to be placed between the left and right parts of the array.

    Here is an example of how your partitioning algorithm might work:

    Initial configuration:
       
    10 7 14 18 6 5 12 23 2 4 81 55
       |                        |
      left                    right
    
    left moves right until it points to 14, which is greater than 10, the pivot. right moves left until it points to 4, which is less than the pivot:
    10 7 14 18 6 5 12 23 2 4 81 55
          |                |
        left             right
    
    We now swap the elements pointed to by left and right:
    10 7 4 18 6 5 12 23 2 14 81 55
         |                 |
        left             right
    
    We now move left right to 18 and right left to 2:
    10 7 4 18 6 5 12 23 2 14 81 55
            |           |
           left       right
    
    Again we swap them:
    10 7 4 2 6 5 12 23 18 14 81 55
           |            |
          left       right
    
    Now left moves left to 12 and right moves right to 5:
    10 7 4 2 6 5 12 23 18 14 81 55
               |  |    
            right left 
    
    As promised, they have now crossed and right is one less than left. You will notice that all elements less than the pivot are in the left part of the array and that all elements greater than the pivot are in the right part of the array. Our last step is to swap the pivot with the element to which right points:
    5 7 4 2 6 10 12 23 18 14 81 55
               |  |    
            right left 
    
    
    Finally we can call quicksort on the left and right parts of the array.

What to Submit

  1. binarySearch.c
  2. quicksort.c (optional)