class Merge implements Merging { public int[] merge (int[] B, int[] C) {your code goes here
} public void choice (int c) {} }Assume that the arrays B and C are already sorted (when you have the whole of mergesort in place they will have just been sorted). Allocate a new array A that's just big enough to contain the merge of B and C. Merge B and C into A, so that A ends up sorted and containing the same stuff as B and C. Draw the diagram showing how merge is going to work. Don't forget to deal with the situation where one of the arrays has been exhausted before the other, for which a simple copy (with no comparisons) is needed. Run the TESTER on run Merge.java in the usual way. The size command line argument controls the size of B; use size2 for C. You can use Trace.printarray (B, j) etc.. to see your code in action. Give it the example above explicitly:
trace Merge.java array=16,46,46,46,61,78,89,91 array2=27,34,37,56,75,81,83,95These arrays are already sorted, so the precondition for merge is satisfied, and you should get a sorted result. Test the situations where all of B comes before all of C, or vice versa. There is no need to time this code: it is only a subroutine, and is pretty obviously linear in the (total) size of the arrays.
class Mergesort implements Sorting { public int[ ] sort (int[ ] A) { int size = A.length;your code goes here
} // access to merge(B,C) private Merging merger; // this is for the hybrid algorithm (Section 6) private int cutoff=0; public void cutoff (int n) { cutoff=n; } private Sorting insertion_sorter; public void choice (int c) {} public Mergesort() { merger = new TestMerge(); // or Merge() to use your own insertion_sorter = new Insertion(); } }Begin by finding the midpoint:
int mid = size/2;Assign this explicitly to a variable - don't just use this expression verbatim in the code. Remember that size may be odd; it is more important to make the calculation of the left and right "halves" consistent than to make mid exactly A.length/2. Now declare two new arrays (B[ ] and C[ ]) of appropriate sizes and copy half of the given array into each of them. Next is where the the recursive calls to sort(B) and sort(C) belong. Write the code, but comment it out (i.e. put // before it) for the time being. Now use merger.merge (B,C) to merge them, and return the result of the merge as the result of sort. The code as given above (with TestMerge) uses the merge method that's built into the TESTER, so you can be confident that this part is correct. Substitute your own code (with Merge) later, when you have mergesort working correctly. Try this out using an array consisting of two sorted halves:
run Mergesort.java array=16,46,46,46,61,78,89,91,27,34,37,56,75,81,83,95There is a pitfall here. If you fall into it, you will get back the same (unsorted) array that you put in. This is to do with the distinction between JAVA variables and the objects (or arrays) to which they refer. You have recently done some exercises in Introduction to Programming concerning this point. If you didn't actually make this mistake, you have missed out on a learning opportunity - alter your code to make this happen. If we had been using C or C++, you would have fallen down this hole much earlier.
run Mergesort.java size=1000000 thread=no check Mergesort.java sizes=200000,500000,1000000 maxtime=60Because of the allocation of scratch space within the recursive calls, you will not be able to run this for very large arrays: 1,000,000 may be the largest that the JAVA run time system allows. Does it make any difference to the performance of merge sort if you give it already-sorted data?
Trace.printmerge (int[] A, int indent, int level, boolean direction);The direction argument is there to show when you enter and leave sort. Call it with true on entry and false on exit; then an appropriate bracket will be printed. The other two arguments keep track of how deeply nested the recursion is, and what part of the array you're working on. You will need to alter your code like this to use them:
public int[] sort (int[] A) { return mergesort (A, 0, 0); } private int[] mergesort (int[] A, int indent, int level) { /* your original code for sort(A) */ }and replace sort(B) with
mergesort (B, new_indent, level+1);and similarly C. The level argument causes that many dots to be printed, to show the depth of the recursion. The indent argument shifts the printout of the array across the screen by some number of cells. Work out what value of indent has to be passed to each of the two recursive calls to align them with the two halves of the larger array from which they came. How many elements of the original array are to the left of the part we're looking at?
class Quicksort implements Sorting { public int[ ] sort (int[ ] A) { return quicksort (A, 0, A.length); } private int[ ] quicksort (int[ ] A, int left, int right) {your code goes here
} // access to split (A, left, right) private Splitting splitter; // this is for the hybrid algorithm private int cutoff=0; public void cutoff (int n) { cutoff=n; } public void choice (int c) {} public Quicksort() { splitter = new TestSplit(); // or Split() to use your own }Do not allocate any new arrays. As with shift(), where_is_min() and where_to_insert(), we shall work with segments of the array, delimited by left and right. As usual, left is inside and right is outside the segment. At the top level, left=0 and right=A.length. The interesting thing about quicksort is how to choose the pivot value. Start by using pivot=A[left]. Call split with appropriate arguments to tell it what segment to consider and what the pivot value is. It re-arranges the segment and returns the position at (before) which to make another split. Call quicksort recursively on the two halves. Where is the sorted result now? Try it out using the TESTER. There is a special tracing routine to let you see how quicksort works:
Trace.printquick (A, left, right, level, direction)As you did with mergesort, you will need to add an argument to quicksort to count the level.
trace quick-sort pivot=firstOther ways of choosing the pivot are last, middle, mean, random and median3. What is meant by the average, mean, median and mode of a collection of numbers? Which of them can be calculated easily? Which of them would you like to use, ideally, to choose the pivot value for quicksort? The first value in the segment is the obvious one to try, but what happens when you run quicksort on already sorted data? Use trace to watch it. Is the last value any better than this? What about the middle one, or one in a random position? The textbooks tell you to use the median of the first, middle and last values. Write the code to do this. It is more complicated than you might like for such a simple job. As is unfortunately rather common, people write textbooks and copy ideas like median-of-three from previous generations of textbooks (but adding the word " JAVA" in fluorescent letters to the cover of the book, to make you but it) without considering the ideas carefully themselves. Do
run quick-sort sawtoothpc=50to see what I mean by a sawtooth array. (I got the word from sawtooth waves, which are used to move the electron beam across a television screen, as my father was an electronics engineer designing televisions.) You can control the position of the vertex of the sawtooth by using sawtooth=2 to put it 2 places from the left, sawtooth=-2 to put it 2 places from the right or sawtoothpc=25 to put it 25% of the way through the array. Do
trace quick-sort sawtooth=1 pivot=median3and guess what the result of check might be before you try it. The rest of this exercise sheet is for the serious programmers.
for (int frag_len = 1; frag_len < size; frag_len *= 2) { for (int from = 0; from < size; from += 2 * frag_len) { // merge B[from...from+frag_len-1] and B[to...to+frag_len-1] // to corresponding segment in A } }When you've done each merge, you can either copy it back, or alternately merge from A[] to B[] and vice versa. Don't forget to make allowance for the size not being exactly a power of 2.
This is www.PaulTaylor.EU/algorithms/merge+quick.html and it was derived from algorithms/merge+quick.tex which was last modified on 21 July 2007.