CS 415, Section 002 | Sonoma State University | Spring, 2022 |
Algorithm Analysis
|
||
Instructor: Henry M. Walker
Lecturer, Sonoma State University |
The following sorting algorithm is called a merge sort, because it is based on a simple procedure that combines or merges two short lists of ordered data into one large, ordered list. With this procedure, the merge sort proceeds from small initial array segments to large ones:
Consider an entire array as a sequence of 1-element array segments, each of which is ordered.
Merge segment 1 with segment 2, segment 3 with segment 4, segment 5 with segment 6, etc. to obtain 2-element array segments, each of which is ordered.
With ordered array segments of size 2, merge segment 1 with segment 2, segment 3 with segment 4, segment 5 with segment 6, etc. to obtain 4-element array segments, each of which is ordered.
With ordered array segments of size 4, merge segment 1 with segment 2, segment 3 with segment 4, segment 5 with segment 6, etc. to obtain 8-element array segments, each of which is ordered.
Continue merging to obtain ordered array segments of size 16, 32, 64, ... .
Stop when the ordered array segment contains the entire array.
To clarify, this process is illustrated in the following diagram:
As this process indicates, for each step, the merge sort considers an array to be a collection of small, ordered segments, and two adjacent segments can be merged to yield a larger, ordered array segment.
In practice, this merging process is subject to several details:
To merge two adjacent array segments, one must know where the first begins (perhaps given by a variable start1), where the second begins (perhaps given by a variable start2), and where the second segment ends (perhaps given by a variable end2). There is no need to keep track of the end of the first segment, as that will always be just before start2
At each stage of processing, a variable (perhaps called mergeSize) keeps track of the current size of the ordered array. Initially, this variable is set to size 1. Thereafter, the variable is doubled with each full iteration.
Starting with one array, merging requires the existence of a second array. In the first step, data are moved from the initial array to the second. However, with all of the data now moved to the second array, the second step may move data from the second array back to the original array. (No need to keep allocating space for new arrays!) Thereafter each merging step can process from one array to the other, followed by merging back.
To keep track of the two arrays, two temporary array variables (perhaps called a0 and a1) may reference the two arrays. Then after each merge step, the arrays designated by these variables may be swapped, so a0 always points to the most recently merged array, and a1 will designate which array will receive the next merge step.
At the end of all merging steps, the fully sorted data will be in one of the two arrays, but some bookkeeping may be needed to determine which array has the sorted data set. If the fully sorted data is not in the original array, then a copy may be needed back to that array.
The following method puts these elements together, assuming the merge method has already been implemented.
/** * sort the array a, using a merge sort */ public static void mergeSort (int initArr [ ]) { int resArr [ ] = new int [initArr.length]; int a0[ ] = initArr; int a1[ ] = resArr; boolean needCopyBack = false; int mergeSize = 1; int start1; while (mergeSize < initArr.length) { int end2; for (start1 = 0; start1 < initArr.length; start1 = end2) { int start2 = start1 + mergeSize; end2 = start2 + mergeSize; merge (a0, a1, start1, start2, end2); } // swap a0, a1 pointers, so a0 is starting array for next merge int temp [ ] = a0; a0 = a1; a1 = temp; mergeSize *= 2; // keep track of which array holds initArr object needCopyBack = !needCopyBack; //print intermediate result, if desired for (int i = 0; i < a0.length; i++) System.out.printf ("%5d", a0[i]); System.out.print ("\n\n"); } //copy result into initArr, as needed if (needCopyBack) { for (int i = 0; i < initArr.length; i++) initArr [i] = a0 [i]; } }
With this main step completed, the remaining work involves merging two sorted array segments. The outline for this merge follows:
As long as items exist in both array segments:
Copy any remaining elements from the first array segment to the new array.
Copy any remaining elements from the second array segment to the new array.
Consistent with the merge sort code above, an appropriate header for this merge method might be:
/** * merge aInit[start1]..aInit[start1+mergeSize] with * aInit[start2]..Init[end2] * with the result placed in aRes * Note: it may be that start2 >= aInit.length, in which case, only the * valide part of aInit[start1] is copied */ private static void merge (int aInit [ ], int aRes [ ], int start1, int start2, int end2)
created 24 April 2001 revised 11 March 2005 revised 9-13 March 2012 revised 3 November 2018 created December, 2021 revised December-January 2021 |
|
For more information, please contact Henry M. Walker at walker@cs.grinnell.edu. |