简体   繁体   中英

Counting inversion using merge sort

I know that there was a plenty of these implementation here in Stack, but I have got a problem which I cannot handle.

First I have implemented the merge sort at khanacademy with javascript, then I rewrite the code to C++, and tried to count number of inversion in an array.

I did the best I could, and spent an hour trying to get understand what have I done wrong. I did search for another implementation here at stack and tried to correct my code. Unfortunately I do not know what am I doing wrong.I think that I count every inversion. Thanks in advance for an assistance with having understood what is wrong.

My code:

int lowhalflength(int p, int q)
{
    return q - p + 1;
}

int highhalflength(int q, int r)
{
    return r - q;
}


int merge(int array[], int p, int q, int r, int lowhalf[], int highhalf[])
{
    int k = p;
    int i;
    int j;
    int count = 0;
    for (int i = 0; k <= q; i++ , k++)
    {
        lowhalf[i] = array[k];
    }
    for (int i = 0; k <= r; i++ , k++)
    {
        highhalf[i] = array[k];
    }

    k = p;
    i = 0;
    j = 0;

    while (i <= (q - p) && j <= r - (q + 1))
    {
        if (lowhalf[i] <= highhalf[j])
        {
            array[k] = lowhalf[i];
            i++;
        }
        else
        {
            array[k] = highhalf[j];
            j++;
            count += q - 1;
        }

        k++;
    }

    while (i < lowhalflength(p, q))
    {
        array[k] = lowhalf[i];
        k++;
        i++;
    }

    while (j < highhalflength(q, r))
    {
        array[k] = highhalf[j];
        k++;
        j++;
    }


    return count;
}

The mergeSort function:

int mergeSort(int array[], int p, int r)
{
    int q = ((p + r) / 2);
    int* lowhalf = new int[lowhalflength(p, q)];
    int* highhalf = new int[highhalflength(q, r)];

    int count = 0;
    if (p < r)
    {
        q = ((p + r) / 2);
        count = mergeSort(array, p, q);
        count += mergeSort(array, q + 1, r);
        count += merge(array, p, q, r, lowhalf, highhalf);
    }
    delete[] lowhalf;
    delete[] highhalf;
    return count;
}

For array [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] the output is 46 while it should be 45.

EDIT: The answer is to change the following line q-1 to q+jk. I found it by myself but I do not know how should I interpret it. Any hint or proof why it is correct will be really desirable.

You can use my code for counting inversion pair and your merge function should look like this in more efficient manner as:

int merge(int *array, int lower, int mid, int upper) {

    // Initialisation of the sizes of two subarrays and subarrays also.
    int left_array_size = mid - lower + 1;
    int right_array_size = upper - mid;
    int left_array[left_array_size], right_array[right_array_size];

    int j = 0;
    for (int i = lower; i <= mid; i++) {
        left_array[j++] = array[i];
    }
    j = 0;
    for (int i = mid + 1; i <= upper; i++) {
        right_array[j++] = array[i];
    }

    // Performing merging in a non-increasing manner and count inversion pairs..
    int i = 0, k;
    j = 0;
    int resultIntermediate = 0;
    for (k = lower; k <= upper; ) {
        if (left_array[i] <= right_array[j]) {
            array[k++] = left_array[i++];
            if (i >= left_array_size)   break;
        }
        else {
            array[k++] = right_array[j++];

            // If a element in left_array_size is greater than an element from
            // right_array_size then rest of all other elements will also be
            // greater than that element of right_array_size because both
            // subarrays are sorted in non-decreasing order.
            resultIntermediate += left_array_size - i;

            if (j >= right_array_size)  break;
        }
    } //end of for loop.


    // Performing merging if i or j doesn't reach to its
    // maximum value i.e. size of the subarrays.
    while (i < left_array_size) {
        array[k++] = left_array[i++];
    }
    while (j < right_array_size) {
        array[k++] = right_array[j++];
    }

    // Returning the result...
    return resultIntermediate;

} //end of the merge function.

And function to count inversion pair

int countInversionPair(int *array, int lower, int upper) {
    int count_inv_pair = 0;
    // Do recusion untill the problem / array can be subdevided.
    if (lower < upper) {

        // Partition the Array into two subproblems.
        int mid = (lower + upper) / 2;

        // Call the countInversionPair() function for these two
        // subarrays / subproblems recursively to count number of
        // inversion for these subproblems / subarrays.
        count_inv_pair = countInversionPair(array, lower, mid);
        count_inv_pair += countInversionPair(array, mid + 1, upper);

        // Merge these two subarrays into a sigle array
        count_inv_pair += merge(array, lower, mid, upper);
    }
    return count_inv_pair;
}

Now you can get number of inversion pair by calling the function from main as:

int count_inv_pair = countInversionPair(array, 0, size - 1);

And now you will get your answer..

Big thanks for all of you guys, especially @Shiv and @WhozCraig, you gave me and idea how to solve it. The answer is to change q-1 to q+jk

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM