Close
Register
Close Window

Data Structures and Algorithms

Chapter 2 Arrays: Searching and Sorting

Show Source |    | About   «  2.10. Mergesort Concepts   ::   Contents   ::   2.12. Quicksort  »

2.11. Implementing Mergesort

2.11.1. Implementing Mergesort

Implementing Mergesort presents a number of technical difficulties. The first decision is how to represent the lists. Mergesort lends itself well to sorting a singly linked list because merging does not require random access to the list elements. Thus, Mergesort is the method of choice when the input is in the form of a linked list. Implementing merge for linked lists is straightforward, because we need only remove items from the front of the input lists and append items to the output list. Breaking the input list into two equal halves presents some difficulty. Ideally we would just break the lists into front and back halves. However, even if we know the length of the list in advance, it would still be necessary to traverse halfway down the linked list to reach the beginning of the second half. A simpler method, which does not rely on knowing the length of the list in advance, assigns elements of the input list alternating between the two sublists. The first element is assigned to the first sublist, the second element to the second sublist, the third to first sublist, the fourth to the second sublist, and so on. This requires one complete pass through the input list to build the sublists.

When the input to Mergesort is an array, splitting input into two subarrays is easy if we know the array bounds. Merging is also easy if we merge the subarrays into a second array. Note that this approach requires twice the amount of space as any of the sorting methods presented so far, which is a serious disadvantage for Mergesort. It is possible to merge the subarrays without using a second array, but this is extremely difficult to do efficiently and is not really practical. Merging the two subarrays into a second array, while simple to implement, presents another difficulty. The merge process ends with the sorted list in the auxiliary array. Consider how the recursive nature of Mergesort breaks the original array into subarrays. Mergesort is recursively called until subarrays of size 1 have been created, requiring \(\log n\) levels of recursion. These subarrays are merged into subarrays of size 2, which are in turn merged into subarrays of size 4, and so on. We need to avoid having each merge operation require a new array. With some difficulty, an algorithm can be devised that alternates between two arrays. A much simpler approach is to copy the sorted sublists to the auxiliary array first, and then merge them back to the original array.

Here is a complete implementation for mergesort following this approach. The input records are in array A. Array temp is used as a place to temporarily copy records during the merge process. Parameters left and right define the left and right indices, respectively, for the subarray being sorted. The initial call to mergeSort would be mergeSort(array, temparray, 0, n-1).

public static <T extends Comparable<T>> void mergeSort(T[] A, T[] temp, int left, int right) {
    if (left == right)                   // List has one record
        return;
    int mid = (left + right) / 2;        // Select midpoint
    mergeSort(A, temp, left, mid);       // Mergesort first half
    mergeSort(A, temp, mid+1, right);    // Mergesort second half
    for (int i = left; i <= right; i++)  // Copy subarray to temp
        temp[i] = A[i];
    // Do the merge operation back to A
    int i1 = left;
    int i2 = mid + 1;
    for (int curr = left; curr <= right; curr++) {
        if (i1 == mid+1) {               // Left sublist exhausted
            A[curr] = temp[i2];
            i2++;
        } else if (i2 > right) {         // Right sublist exhausted
            A[curr] = temp[i1];
            i1++;
        } else if (temp[i1].compareTo(temp[i2]) <= 0) {  // Get smaller value
            A[curr] = temp[i1];
            i1++;
        } else {
            A[curr] = temp[i2];
            i2++;
        }
    }
}
def mergeSort(A, temp, left, right):
    if left == right:                 # List has one record
        return
    mid = (left + right) // 2         # Select midpoint
    mergeSort(A, temp, left, mid)     # Mergesort first half
    mergeSort(A, temp, mid+1, right)  # Mergesort second half
    for i in range(left, right+1):    # Copy subarray to temp
        temp[i] = A[i]
    # Do the merge operation back to A
    i1 = left
    i2 = mid + 1
    for curr in range(left, right+1):
        if i1 == mid+1:               # Left sublist exhausted
            A[curr] = temp[i2]
            i2 += 1
        elif i2 > right:              # Right sublist exhausted
            A[curr] = temp[i1]
            i1 += 1
        elif temp[i1] <= temp[i2]:    # Get smaller value
            A[curr] = temp[i1]
            i1 += 1
        else:
            A[curr] = temp[i2]
            i2 += 1

Here is a visualization for the merge step.

Settings

Proficient Saving... Error Saving
Server Error
Resubmit

   «  2.10. Mergesort Concepts   ::   Contents   ::   2.12. Quicksort  »

nsf
Close Window