CS140 -- Lab 8
This lab is designed to give you practice with using recursion.
Materials
You will need the following files:
- Executables for the answers are in the directory
/home/bvz/cs140/labs/lab8. As usual, if you have
questions about how these programs should work, try these.
- There are two sample data files named numbers1.txt
and qsort_data.txt in /home/bvz/cs140/labs/lab8
that you should copy to your directory.
- There are two driver files named driver.c and
qdriver.c in /home/bvz/cs140/labs/lab8
that you should copy to your directory.
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:
- Compile the file and execute it
- 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.
- 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:
- an integer key to be located.
- an array of integer data to be searched. The data will be in ascending
order and you may assume there are no duplicates.
- a beginning index at which to start searching.
- 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:
- If end is less than begin, then key is not in the array, so
return -1.
- 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.
- 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.
- 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:
- You may assume that your data consists of integers and that
all the integers are unique.
- The pivot is the first element in the array.
- 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.
- 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:
- 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.
- 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.
- If left is still less than right, then
swap the two elements to which they point.
- 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
- binarySearch.c
- quicksort.c (optional)