CS 261 University of Puget Sound Spring, 2020
 
Computer Science II
Abstract Data Types and their Implementations, Some Basic Algorithms,
Object-oriented Problem Solving, and Efficiency
 

Warning: This course is under development. Although the basic structure of this course is largely established, nothing on this Web site should be considered official or even possibly correct.
DO NOT MAKE PLANS BASED ON THE CONTENTS OF THIS SITE UNTIL JANUARY, 2020.

Merge Sort and Timing Algorithms

Goals

This laboratory exercises provides some practice with the merge sort and outlines a mechanism for determining experimentally the efficiency of various algorithms.

The Merge Sort

Many applications require the maintenance of ordered data. Already we have examined the Selection Sort and the Insertion Sort. The first part of this lab examines the Merge Sort.

As noted in the reading for the Merge Sort, the merge sort is motivated by the observation that merging two sorted arrays (or array segments) into another is reasonably straight forward:

In practice, some care is needed in coding, so that one copies just the relevant array segments and one does not go beyond the bounds of either initial array segment.

With this notion of merging, a merge sort proceeds as follows:

In this process, one needs to copy elements in one array into a second array. Since copying the array elements back to the original array takes time, the idea is to first merge from one array to a second, and then to merge from the second to the first. At the end, the sorted items will be in one of the two arrays, and some carefully bookkeeping can determine whether one copy is needed at the end to move data to the original array.

As already indicated, entire process depends upon merging two adjacent (and ordered) array segments into the corresponding place in a second array. In practice, this suggests the following method header:

      /** 
     * 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
     *        valid part of aInit[start1] is copied
     */
    private static void merge (int aInit [ ], int aRes [ ],
		   int start1, int start2, int end2)

Here, the ordered array segment aInit[start1]..aInit[start2-1] is merged with the following ordered array segment aInit[start2]..aInit[end2]

With this method implemented, the main merge sort algorithm becomes:

    /** 
     * 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;
		
	    }

	//copy result into initArr, as needed
	if (needCopyBack)
	    {
		for (int i = 0; i < initArr.length; i++)
		    initArr [i] = a0 [i];
	    }
    }
  1. Describe, in your own words, how the Merge Sort works. Your description should include comments about the following:

    1. What is the purpose of the variable needCopyBack?
    2. The algorithm starts with array segments of size 1, and subsequent processing utilizes array segments of size 2, 4, 8, ... (all powers of 2). What happens if the array's size is not a power of two?
    3. What size are the two auxiliary arrays a0 and a1? Why can these same arrays be used for all subsequent processing, regardless of the array-segment size?
  2. Implement the merge method, as described.

  3. Annotate the code for the mergeSort method, explaining in some detail what each line (or small collection of lines) accomplishes.

Analysis and Timing

The selection sort, insertion sort, and merge sort each yield their own analyses of efficiency.

  1. For each algorithm, identify circumstances under which the best case and the worst case analyses could occur. What is the order of each sorting algorithm in the best case and in the worst case?

  2. Program SortShell.java combines the code for the selection, insertion, and merge sorts, although the merge sort is incomplete (a stub is available for the mergeSort method, but it is not implemented). Copy this program to Eclipse.

  3. Insert your merge method, so that the program is complete. Review the program to determine how it works, and run it to observe its output.

  4. The program provides timings, but how might we know that the sorting algorithms are functioning properly? Not only should a resulting array be sorted, but it also should contain all of the original array values — just in a [possibly] different order. It seems unlikely that we would be able to check carefully output of an array with 100,000 values, so testing will have to be automated. Describe how one might perform tests to help confirm the output is correct in each case. Then, add these tests to the code. The resulting code might perform a range of checks, and just report if/when errors arise (certainly, the checking should produce rather little output).

  5. In reviewing the various timings of algorithms, what algorithm(s) do you think should be used in various contexts (e.g., for ascending data, for random data, and for descending data). Explain your conclusions.


created 24 April 2001
revised 28 April 2006
revised 11-13 March 2012
revised 2-3 November 2018
revised and reorganized 23 January 2020
Valid HTML 4.01! Valid CSS!
For more information, please contact Henry M. Walker at walker@cs.grinnell.edu.