利用归并排序求逆序数

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_26658823/article/details/74275967

  假设A[1…n]是一个有n个不同元素的数组,若i < j 且 A[i] > A[j],则对偶(i, j)称为A的一个逆序对。例如,对于数组[2, 3, 8, 6, 1],它的所有逆序对为(1, 5),(2, 5),(3, 4),(3, 5),(4, 5),共有5个逆序对,所以逆序数为5。
  当数组中元素数量较少时,我们可以通过手工计算数组的逆序数;但是如果数组中元素比较多时,手工计算比较麻烦,我们可以利用归并排序来计算数组的逆序数。归并排序的思路是将数组A[1…n]分成A[1…mid]和A[mid+1…n]分别进行归并排序,然后再将这两个排好序的数组合并。在合并的过程中(假设按从小到大排序,1 <= i <= mid 且 mid + 1 <= j <= n),当A[i] <= A[j]时,没有逆序对;当A[i] > A[j]时,A[1…mid]中比A[i]大的数都比A[j]大,又因为A[j]要放在A[i]前面,所以当前的逆序数就等于mid - i + 1。把所有归并过程中的逆序数加起来就是原数组的逆序数。

    //归并排序求逆序数的代码
    static int merge(int* arr, int low, int mid, int high)
    {
        int cnt = 0;
        int len = sizeof arr / sizeof *arr;
        int tmp[len];

        //将数组arr中的元素存到tmp中
        for(int k = low;k <= high;k++)
            tmp[k] = arr[k];

        for(int k = low, i = low, j = mid + 1;k <= high;k++){
            //左半边元素用完了
            if(i > mid)              arr[k] = tmp[j++];
            //右半边元素用完了
            else if(j > high)        arr[k] = tmp[i++];
            //右边元素小于左边的元素
            else if(tmp[j] < tmp[i]) arr[k] = tmp[j++],cnt += mid - i + 1;
            //左边的元素小于右边的元素
            else                     arr[k] = tmp[i++];
        }
        return cnt;
    }

    int merge_sort(int* arr, int low, int high)
    {
        int ans = 0;
        if(low < high){
            int mid = low + (high - low) / 2;
            ans += merge_sort(arr, low, mid);
            ans += merge_sort(arr, mid + 1, high);
            ans += merge(arr, low, mid, high);
        }
        return ans;
    }
展开阅读全文

没有更多推荐了,返回首页