Nothing special here. It’s just a blog post for summarising my algorithm learning course. Here are some questions related to merge sort.

Merging with smaller auxiliary array

Question

Suppose that the subarray a[0] to a[n-1] is sorted and the subarray a[n] to a[2*n-1] is sorted. How can you merge the two subarrays so that a[0] to a[2*n-1] is sorted using an auxiliary array of length n (instead of 2n)?

Answer

Instead of copying the whole array into the auxiliary array, copy only the left half to that auxiliary array (a[0] to a[n-1]). At this time, the first half of the original array is free to overwrite any value. Apply merge sort and write the result back to the original array, from the first position. You will always have enough space in the original array to do that.

Counting inversions

Question

An inversion in an array a[] is a pair of entries a[i] and a[j] such that i<j but a[i]>a[j]. Given an array, design a linearithmic algorithm to count the number of inversions.

Answer

Actually, I couldn’t think of a solution for this even with the hint. Here is the solution that I found on the internet but it is also interesting to take a look :D I would give 1 like for the one that could think of the solution for this if I met him :LOL: It took me about 10 min to understand…

The basic idea is to use merge sort and count while merging the 2 arrays. In merge process, let i is used for indexing left sub-array and j for right sub-array. At any step in merge(), if a[i] is greater than a[j], then there are (mid – i) inversions. because left and right subarrays are sorted, so all the remaining elements in left-subarray (a[i+1], a[i+2] … a[mid]) will be greater than a[j]. Here is the sample implementation in Java

class Test {
    // This method sorts the input array and returns
    // the number of inversions in the array
    static int mergeSort(int arr[], int array_size) {
        int temp[] = new int[array_size];
        return _mergeSort(arr, temp, 0, array_size - 1);
    }

    // An auxiliary recursive method that sorts the input array and
    // returns the number of inversions in the array.
    static int _mergeSort(int arr[], int temp[], int left, int right) {
        int mid, inv_count = 0;
        if (right > left) {
            // Divide the array into two parts and call _mergeSort()
            // for each of the parts
            mid = (right + left) / 2;

            // Inversion count will be sum of inversions in left-part, right-part
            // and number of inversions in merging */
            inv_count = _mergeSort(arr, temp, left, mid);
            inv_count += _mergeSort(arr, temp, mid + 1, right);

            // Merge the two parts
            inv_count += merge(arr, temp, left, mid + 1, right);
        }
        return inv_count;
    }

    // This method merges two sorted arrays and returns inversion count in
    // the arrays.
    static int merge(int arr[], int temp[], int left, int mid, int right) {
        int i, j, k;
        int inv_count = 0;

        i = left; // i is index for left subarray
        j = mid;  // j is index for right subarray
        k = left; // k is index for resultant merged subarray
        while ((i <= mid - 1) && (j <= right)) {
            if (arr[i] <= arr[j]) {
                temp[k++] = arr[i++];
            } else {
                temp[k++] = arr[j++];

                // THE MAGIC HAPPENS HERE
                // this is tricky -- see above explanation for merge()
                inv_count = inv_count + (mid - i);
            }
        }

        // Copy the remaining elements of left subarray
        // (if there are any) to temp
        while (i <= mid - 1)
            temp[k++] = arr[i++];

        // Copy the remaining elements of right subarray
        // (if there are any) to temp
        while (j <= right)
            temp[k++] = arr[j++];

        // Copy back the merged elements to original array
        for (i = left; i <= right; i++)
            arr[i] = temp[i];

        return inv_count;
    }
}