Summary: We continue our exploration of sorting algorithms by considering the famous merge sort algorithm.
Prerequisite Knowledge: The sorting infrastructure, covered in the lab on quadratic sorts.
If you have not done so already, fork and clone the repository at https://github.com/Grinnell-CSC207/sorting.
The file MergeSorter.java has a partial implementation of the standard recursive merge sort algorithm.
a. Why do you think we call
before doing the recursive calls to
b. Why is the program so short?
c. Create a short experiment for the
in MergeSorter.java. Minimally, you should write a class whose
main method builds a
MergeSorter, builds an
array, builds an appropriate comparator, calls the
sort method using the array, and then prints
d. Do you expect the algorithm/method to work correctly? Why or why not?
e. Check your answer experimentally.
As you have probably discovered, the merge sort algorithm doesn't
work as currently implemented. Why? Because the
Utils.merge method is not implemented.
a. Sketch invariants for the merge method. You will likely want to draw pictures of the three arrays that you'll be working with. You'll also likely have an index into each array that you'll want to keep in the sketch.
b. Based on your invariants, implement that method.
c. You can choose to write experiments and tests for
Utils.merge or you can hope that the
experiment and tests for
will help you identify any errors you might have.
If you find that you have extra time, attempt one or both of the following.
Merge sort is supposedly an O(nlog2n) algorithm. But it's sometimes useful to gather data to see if the actual performance matches the expected performance.
Utils.java to add a step counter. Each time you
do an assignment to the array in
merge, increment that
b. Write an experiment in which you build random arrays of size 100, 200, 400, 800, and 1600 and have the program count the number of assignments required for each size. (Don't forget to reset the counter between arrays!)
c. Sketch a graph of your data to see if you get the expected behavior. (For an O(nlog2n) algorithm, we'd expect that the running time of the algorithm would slightly more than double each time we double the input size.
d. Do you think counting the number of times we put a value in the result array is a reasonable proxy for the number of steps? Why or why not?
Iterative merge sort is an algorithm that works bottom up, rather than top-down. First you merge neighboring elements into sorted pairs. (You may have one element left at the end.) Then you merge all neighboring sorted pairs into sorted 4-tuples. (You may have a singleton, pair, or triple left over.) Then you merge all neighboring sorted 4-tuples into sorted 8-tuples. (You may have a tuple of size less than eight left over.) And so on and so forth.
IterativeMergeSorter.java has a sketch of this algorithm. Finish implementing the algorithm.
Note that you may find it helpful to draw a picture of the expected state of the system before and after one round. And yes, such a picture serves as a form of loop invariant.