Is there a way to make this MergeSort algorithm more efficient?

Viewed 60

So I have this algorithm for MergeSort, and I need to reduce the number of compares. I'm not allowed to use any extra data structures other than the ones I already have. I'm completely stumped as to how I can make this more efficient. Can anyone help?

int compares = 0;

// Merge two sorted subarrays arr[low .. mid] and arr[mid + 1 .. high]
void Merge(int arr[], int aux[], int low, int mid, int high)
{
    int k = low, i = low, j = mid + 1;

    // While there are elements in the left and right runs
    while (i <= mid && j <= high)
    {
        if (arr[i] <= arr[j])
            aux[k++] = arr[i++];
            compares++;
        else
            aux[k++] = arr[j++];
    }

    // Copy remaining elements
    while (i <= mid)
        aux[k++] = arr[i++];

    // No need to copy the second half

    // copy back to the original array to reflect sorted order
    for (int i = low; i <= high; i++)
        arr[i] = aux[i];
}

// Sort array arr [low..high] using auxiliary array aux
void MergeSort(int arr[], int aux[], int low, int high)
{
    // Base case
    if (high == low)    // if run size == 1
        return;

    // find mid point
    int mid = (low + ((high - low) >> 1));

    // recursively split runs into two halves until run size == 1,
    // then merge them and return back up the call chain

    MergeSort(arr, aux, low, mid);      // split / merge left  half
    MergeSort(arr, aux, mid + 1, high); // split / merge right half

    Merge(arr, aux, low, mid, high);    // merge the two half runs
}
1 Answers

There are some problems in your code:

  • the Merge function is incorrect: the remaining elements from the right array are not copied to the aux array, which is fine (No need to copy the second half), but the final loop that copies the element back to arr should stop at i < k instead of running to i <= high

  • The compares counter is only incremented if the comparison yields true.

  • The else clause is a syntax error because there are 2 statements after the if that are not grouped as a block.

Here is a corrected version:

int compares = 0;

// Merge two sorted subarrays arr[low .. mid] and arr[mid + 1 .. high]
void Merge(int arr[], int aux[], int low, int mid, int high) {
    int k = low, i = low, j = mid + 1;

    // While there are elements in the left and right runs
    while (i <= mid && j <= high) {
        compares++;
        if (arr[i] <= arr[j])
            aux[k++] = arr[i++];
        else
            aux[k++] = arr[j++];
    }

    // Copy remaining elements
    while (i <= mid)
        aux[k++] = arr[i++];

    // No need to copy the second half

    // copy back to the original array to reflect sorted order
    for (int i = low; i < k; i++)
        arr[i] = aux[i];
}

// Sort array arr [low..high] using auxiliary array aux
void MergeSort(int arr[], int aux[], int low, int high) {
    // Base case
    if (high == low)    // if run size == 1
        return;

    // find mid point
    int mid = low + ((high - low) >> 1);

    // recursively split runs into two halves until run size == 1,
    // then merge them and return back up the call chain

    MergeSort(arr, aux, low, mid);      // split / merge left  half
    MergeSort(arr, aux, mid + 1, high); // split / merge right half

    Merge(arr, aux, low, mid, high);    // merge the two half runs
}

Reducing the number of comparison is not possible in the general case but if the array is known to have substantial portions that are already sorted, an extra initial comparison may allow for a substantial reduction in the total number of comparisons:

int compares = 0;

// Merge two sorted subarrays arr[low .. mid] and arr[mid + 1 .. high]
void Merge(int arr[], int aux[], int low, int mid, int high) {
    int k = low, i = low, j = mid + 1;

    // Extra comparison to improve special case of sorted arrays
    if (high - low > 7) {
        compares++;
        if (arr[mid] <= arr[j])
            return;
    }
    // While there are elements in the left and right runs
    while (i <= mid && j <= high) {
        compares++;
        if (arr[i] <= arr[j])
            aux[k++] = arr[i++];
        else
            aux[k++] = arr[j++];
    }

    // Copy remaining elements
    while (i <= mid)
        aux[k++] = arr[i++];

    // No need to copy the second half

    // copy back to the original array to reflect sorted order
    for (int i = low; i < k; i++)
        arr[i] = aux[i];
}
Related