Assignment #3

Pencil & Paper:

On page 59, Weiss suggests that the algorithm in Figure 2.11 has a T(n) of about 2 log n, counting only the multiplication’s. He goes on to mention 3 alternative forms for line 6 in the algorithm. Derive T(n) as a recurrence relationship for the algorithm when line 6c is used in place of the original line 6. Solve the recurrence relationship in order to get T(n), then conclude with the perfromance in Big-O notation.

Hint: simplify things a bit by assuming that the then-clause is executed on every call. This will clearly require more instructions than the actual algorithm will execute.

Programming

The purpose of this exercise is to develop skills in empirical determination of algorithm performance as a function of data set size. We will use the problem of generation of random permutations. Since you developed a random permutation generation function and driver program in the previous assignment, that will be a good starting point.

You should also read exercise 2.8 in the text. There, 3 algorithms are described in order of increasing efficiency. Since the algorithm was not specified for Assignment 2, you might have used any one of these, or another of your own design. You can use the one you actually programmed, or implement another one for this assignment. (Be sure to say which one you are using!) Also, if you did not use the Random.cpp and Random.h from the Weiss Web site, you will have to go back and revise your code to use it. The rand() function from the C library will not work well enough for the size of n you will need in this assignment. And, if you used an array of fixed size, you should change to dynamic allocation, i.e.,

cin >> n;

int* a = new int[n];

Finally, you will need to modify the driver program to report the time required to generate a random permutation of size n. Use the C++ clock() function to measure the run time, e.g.,

clock_t start, finish;

start = clock();

randomPerm(n, a)

finish = clock();

cout << (float)(finish - start)/CLOCKS_PER_SEC << endl;

The prototypes for the time functions are in time.h.(or ctime).

Then, run the driver program for various values of n, recording the reported run times. You will have to adjust the values used in accordance with the speed of your algorithm and the speed of your machine. For example, Floyd’s algorithm (algorithm 3, exercise 2.8) on a fast machine may require n > 20,000 to get a measurable run time, whereas the first algorithm mentioned in Exercise 2.8 will probably require smaller values in order to complete in tolerable amount of time. In my experience, with a 166 MHz Pentium class machine, n should be varied between 2000 and 40000 for algorithm 2, and between 10,000 and 1,000,000 for Floyd’s algorithm. Note that with n this large you cannot easily do this assignment with a 16-bit compiler.

See section 2.4.5 and Figure 2.13 for the way you should compare your data to the theoretical T(n). For example, if Floyd’s algorithm is O(n), then T(n)/n should approach some constant value as n gets very large. Use a spreadsheet program to tabulate and plot your results.  See resultsStraw.xls in our download area for an example of how to do this with Excel.
Submit your source code and program output as usual, and also submit a plot of T(n)/f(n) versus n (n must be on the horizontal axis). Here, f(n) is the Big-O function that you believe is appropriate for T(n). Hint: T(n)/f(n) should approach an horizontal asymptote.