利用归并排序求逆序数

来源:互联网 发布:c 语言课程主要内容 编辑:程序博客网 时间:2024/06/05 20:49

  假设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;    }
原创粉丝点击