One of the most important, and well-studied, problems in computing is that of sorting. It comes in various guises, but essentially the problem is this: Given a collection of values of some type —and a total ordering1 on that type— produce a list/sequence of those values in ascending order (from "smallest" to "largest").
For this assignment, the focus is on sorting an array using a particular recursive sorting algorithm that we will call Split/Coalesce Sort.
Expressed at a slightly higher level than Java code, one version of the Split/Coalesce algorithm to sort the array segment a[low..high) goes like this:
As an example, suppose that the situation is as depicted here:
|low mid |high +-----------+---+---+---+---+---+---+---+---+---+---+---+-----------+ a | ... | 8 | 3 |17 | 4 |11 | 5 | 0 |21 | 2 | 3 | 9 | ... | +-----------+---+---+---+---+---+---+---+---+---+---+---+-----------+ |
Step 1 computes mid to be where it is shown in the diagram above.
Steps 2 and 3 establish this:
0 1 2 3 4 +---+---+---+---+---+ leftHalf | 8 | 3 |17 | 4 |11 | +---+---+---+---+---+ |
0 1 2 3 4 +---+---+---+---+---+ leftHalf | 3 | 4 | 8 |11 |17 | +---+---+---+---+---+ |
After step 2 | After step 3 |
---|
Steps 4 and 5 establish this:
0 1 2 3 4 5 +---+---+---+---+---+---+ rightHalf | 5 | 0 |21 | 2 | 3 | 9 | +---+---+---+---+---+---+ |
0 1 2 3 4 5 +---+---+---+---+---+---+ rightHalf | 0 | 2 | 3 | 5 | 9 |21 | +---+---+---+---+---+---+ |
After step 4 | After step 5 |
---|
The most complicated part of the algorithm is Step 6, in which the elements of leftHalf[] and rightHalf[] are coalesced. Below we illustrate the effects of the first five iterations of that process when applied to our ongoing example. The elements of a[low..high) are shown as -'s because they will all be overwritten during the coalescing process, without regard to whatever values are stored there.
0 1 2 3 4 +---+---+---+---+---+ leftHalf | 3 | 4 | 8 |11 |17 | +---+---+---+---+---+ i |
0 1 2 3 4 5 +---+---+---+---+---+---+ rightHalf | 0 | 2 | 3 | 5 | 9 |21 | +---+---+---+---+---+---+ j |
|low |high +-----------+---+---+---+---+---+---+---+---+---+---+---+-----------+ a | ... | - | - | - | - | - | - | - | - | - | - | - | ... | +-----------+---+---+---+---+---+---+---+---+---+---+---+-----------+ k |
0 1 2 3 4 +---+---+---+---+---+ leftHalf | 3 | 4 | 8 |11 |17 | +---+---+---+---+---+ i |
0 1 2 3 4 5 +---+---+---+---+---+---+ rightHalf | 0 | 2 | 3 | 5 | 9 |21 | +---+---+---+---+---+---+ j |
|low |high +-----------+---+---+---+---+---+---+---+---+---+---+---+-----------+ a | ... | 0 | - | - | - | - | - | - | - | - | - | - | ... | +-----------+---+---+---+---+---+---+---+---+---+---+---+-----------+ k |
0 1 2 3 4 +---+---+---+---+---+ leftHalf | 3 | 4 | 8 |11 |17 | +---+---+---+---+---+ i |
0 1 2 3 4 5 +---+---+---+---+---+---+ rightHalf | 0 | 2 | 3 | 5 | 9 |21 | +---+---+---+---+---+---+ j |
|low |high +-----------+---+---+---+---+---+---+---+---+---+---+---+-----------+ a | ... | 0 | 2 | - | - | - | - | - | - | - | - | - | ... | +-----------+---+---+---+---+---+---+---+---+---+---+---+-----------+ k |
0 1 2 3 4 +---+---+---+---+---+ leftHalf | 3 | 4 | 8 |11 |17 | +---+---+---+---+---+ i |
0 1 2 3 4 5 +---+---+---+---+---+---+ rightHalf | 0 | 2 | 3 | 5 | 9 |21 | +---+---+---+---+---+---+ j |
|low |high +-----------+---+---+---+---+---+---+---+---+---+---+---+-----------+ a | ... | 0 | 2 | 3 | - | - | - | - | - | - | - | - | ... | +-----------+---+---+---+---+---+---+---+---+---+---+---+-----------+ k |
0 1 2 3 4 +---+---+---+---+---+ leftHalf | 3 | 4 | 8 |11 |17 | +---+---+---+---+---+ i |
0 1 2 3 4 5 +---+---+---+---+---+---+ rightHalf | 0 | 2 | 3 | 5 | 9 |21 | +---+---+---+---+---+---+ j |
|low |high +-----------+---+---+---+---+---+---+---+---+---+---+---+-----------+ a | ... | 0 | 2 | 3 | 3 | - | - | - | - | - | - | - | ... | +-----------+---+---+---+---+---+---+---+---+---+---+---+-----------+ k |
0 1 2 3 4 +---+---+---+---+---+ leftHalf | 3 | 4 | 8 |11 |17 | +---+---+---+---+---+ i |
0 1 2 3 4 5 +---+---+---+---+---+---+ rightHalf | 0 | 2 | 3 | 5 | 9 |21 | +---+---+---+---+---+---+ j |
|low |high +-----------+---+---+---+---+---+---+---+---+---+---+---+-----------+ a | ... | 0 | 2 | 3 | 3 | 4 | - | - | - | - | - | - | ... | +-----------+---+---+---+---+---+---+---+---+---+---+---+-----------+ k |
What the reader should have inferred from this sequence of diagrams is that during each iteration of Step 6 (the "coalescing" process), the values leftHalf[i] and rightHalf[j] are compared and the smaller of the two is copied into (i.e., assigned to) a[k]. (In case of a tie, as occurred during the third iteration, it does not matter which one we choose.) Of course, k increases by one, as does one among i and j (according to whether the smaller value was leftHalf[i] or rightHalf[j] respectively).
The loop invariant is this:
Of course, at some point during the coalescing process, either i will become equal to leftHalf.length or j will become equal to rightHalf.length. In the former (respectively, latter) case, rightHalf[j..rightHalf.length) (respectively leftHalf[i..leftHalf.length)) should be copied into a[k..high).
Its coalesce() method is also left for the student to complete. It need not be recursive, but ambitious students are encouraged to attempt a recursive solution once they have gotten a loop-based version to work correctly.
The student will notice that each of the sort() and coalesce() methods ends with an assert statement whose purpose is to verify that, upon completion of the method, the relevant array segment's elements are in ascending order. This is to aid debugging. To enable assertion testing, follow the instructions here.
Addition/Optional:
Students having sufficient ambition are encouraged, after they have
completed a correct version of SplitCoalesceSorter_int,
to modify it so as to produce a generic version of that class,
capable of sorting arrays containing values of any (reference)
type, consistent with a total ordering defined by a Comparator
(i.e., an instance of a class that implements the
java.util.Comparator interface) that was provided to the
constructor.
Relevant Java artifacts to support the student's endeavor are these:
Note: In the generic version of the class, the same statement will work, except that leftHalf[] would be declared to be of type T[] rather than int[]. End of note.
The algorithm by which to coalesce two arrays into the segment of another array includes a step that involves copying the elements of one array segment into another one. As an example, suppose that the elements of leftHalf[i..M) are to be copied into a[k .. k+M-i). This is accomplished using the System.arraycopy() method, as follows:
The parameters are as follows: