Computer Science 132
Introduction To Computing II

Dickinson College
Fall Semester 2001
Grant Braught

Lab #6 - "O(n lg n) Sorting with Merge Sort"

Introduction

In this lab you will be implementing the Merge Sort algorithm. Our text introduced the Selection Sort algorithm for sorting a list of values. We saw that Selection Sort has O(n2) complexity, meaning that in the worst case it takes on order n2 steps to sort n values. It was also mentioned that efficient sorting algorithms have O(n log n) complexity. The Merge Sort algorithm is one such algorithm.

The Merge Sort algorithm works by breaking a list of values into two halves, sorting each half and then merging the results to form an ordered list. For example:

Here, once the two halves were sorted (e.g. [2 3 5 9] and [0 4 6 8]) the lists were merged by repeatedly removing the smallest value from the two lists and placing it at the end of a new list. Note that the smallest value will always be the first value in one of the two lists. For example the steps involved in merging the two sorted halves above are:

Of course the question arises of how the two halves of the list get sorted. Well, sorting the two halves requires solving two SMALLER VERSIONS OF THE SAME PROBLEM and then merging the results. Thus, the two halves can be sorted using the Merge Sort algorithm. For example:

Because Merge Sort can be described by solving several smaller versions of the same problem, it is easy to define recursively. Merge Sort can be defined recursively as:

Here the base case says that if a list has only 1 element, then it is already sorted. The recursive case says that, if the list has more than one element then split it into two halves, sort the halves and then merge the results.

Assignment

Write a program that:

  1. Prompts the user for a filename.
  2. Constructs an array of integers from the data in the file (see below).
  3. Uses the Merge Sort algorithm to sort the list.
  4. Displays the list of integers on the screen (10 values to a line.)

Call your program MergeSort and save it as MergeSort.java in the cs132/lab6/ directory in your home directory.

Bonus: Explain in your own words why the MergeSort algorithm is a O(n lg n) algorithm.

Programming Hints

It is suggested that you develop the MergeSort program in a step-by-step manner. One possibility is to first design, write and test a method for merging two sorted arrays of integers. Once that is working, design, write and test code for a method that copies a slice of one array of integers into another array of integers. Next design, write and test code for reading a list of integers from a file into an array. Finally, write and test a recursive method that merge sorts an array of integers. You will probably find it useful to first develop a general strategy for solving each of these sub-problems. Refine this general strategy into a rough algorithm and then into a pseudo-code algorithm. When you have a pseudo-code algorithm that work translate it into java.

A Method for Merging Lists:

The following is a specification for a method that you might use to merge two lists:

/** * Merge two lists that are in non-decreasing order into * a single list that is in non-decreasing order. * * @param x1 a reference to an array of integers in * non-decreasing order. * @param x2 a reference to an array of integers in * non-decreasing order. * @return a reference to a newly created array of * integers that contains the elements of x1 * and the elements of x2 in non-decreasing * order. */ static int[] merge(int[] x1, int[] x2) { }

If the merge method were called as follows:

int[] a = {2, 3, 5, 9}; int[] b = {0, 4, 6, 8}; int[] c; c = merge(a, b);

then, following the call the contents of the array referred to by c would be: [0 2 3 4 5 6 8 9]. You should think carefully about the algorithm that you are going to use to merge the two lists before you begin coding. I suggest developing a general strategy and refining that into a rough algorithm and then into a pseudo code algorithm which is ultimately translated into java.

Copying Slices of an Array:

In order to merge sort a list, it is necessary to break the list into two halves. The following is a description for a method that copies a specified part of an array into a newly created array, and returns a reference to that new array.

/** * Copy a specified region of an array into a new * array and return a reference to the new array. * * @param x a reference to an array. * @param start the index at which to start the copy. * @param end the index at which to end the copy. * @return a reference to a new array that contains the * elements [start ... end] of the array referred to * by x. */ static int[] copySlice(int[] x, int start, int end) { }

The copySlice method will be useful for splitting an array into two halves. For example:

int[] z = {2, 3, 5, 9, 0, 4, 6, 8}; int[] leftHalf; int[] rightHalf; leftHalf = copySlice(z, 0, 3); rightHalf = copySlice(z, 4, 7);

This code sets leftHalf to refer to an array of integers containing [2 3 5 9] and rightHalf to refer to an array of integers containing [0 4 6 8].

Reading Values from a File:

To read an array of integers from a file you will need to download the DiskIO.class file to your lab6 directory. (NOTE: The DiskIO.class file has been updated since lab5 so you must download a new copy!).

Once you have downloaded the DiskIO.class file you will want to download the data file mergeSortData.txt to your lab6 directory. This file that contains 10,000 integers to be sorted. You can test that you have downloaded DiskIO.class and mergeSortData.txt correctly by trying the following program which prints out the contents of the data file one integer per line:

class DiskIOTest { public static void main (String[] args) { int[] x; x = DiskIO.file2IntArray("mergeSortData.txt"); for (int i=0; i<x.length; i++) { System.out.println(x[i]); } } }

The Merge Sort Method:

Once you reach this point writing the merge sort method should be almost trivial. You need only to implement the recursive definition given in the introduction. The following is one possible specification for a mergeSort method.

/** * Merge sort an array of integers into non-decreasing * order. * * @param x a reference to an array of integers. * @return a reference to an array that contains the * integers in x sorted into non-decreasing * order. */ static int[] mergeSort(int[] x) { }

This method will need to implement the base case which, if the array contains only one element, returns that array. If the array has more than one element the array must be split into two halves, which are then sorted using merge sort. The arrays returned from those two merge sorts are merged and returned as the result. As an example of how the mergeSort method would work, consider the following code:

int[] z = {5, 2, 9, 3, 4, 0, 8, 6}; z = mergeSort(z);

Following the execution of this call to mergeSort, z is a reference to an array containing the values [0 2 3 4 5 6 8 9].

If you are having difficulty seeing how to write the mergeSort method you might study the TowersOfHanoi.java program and the RecursiveBinarySearch.java program.

Handing in the Lab