用归并排序处理逆序对问题

首先了解一下什么是逆序对,

对于一个包含N个非负整数的数组A[1..n],如果有i < j,且A[ i ]>A[ j ],则称(A[ i] ,A[ j] )为数组A中的一个逆序对。

例如, 数组(3,1,4,5,2)的逆序对有(3,1),(3,2),(4,2),(5,2),共4个。

然后了解一下什么是归并排序:
void Merge(int a[] , int low, int mid, int high,int b[]) {
    int i = low; // i是第一段序列的下标
    int j = mid + 1; // j是第二段序列的下标
    int k = 0; // k是临时存放合并序列的下标
                // b是临时合并序列
    // 扫描第一段和第二段序列,直到有一个扫描结束
    while (i <= mid && j <= high) {
        // 判断第一段和第二段取出的数哪个更小,将其存入合并序列,并继续向下扫描
        if (a[i] <= a[j]) {
            b[k] = a[i];
            i++;
            k++;
        } else {
            b[k] = a[j];
            j++;
            k++;
        }
    }
    // 若第一段序列还没扫描完,将其全部复制到合并序列
    while (i <= mid) {
        b[k] = a[i];
        i++;
        k++;
    }
    // 若第二段序列还没扫描完,将其全部复制到合并序列
    while (j <= high) {
        b[k] = a[j];
        j++;
        k++;
    }
    // 将合并序列复制到原始序列中
    for (k = 0, i = low; i <= high; i++, k++) {
        a[i] = b[k];
    }
}
void MergeSort(int a[],int low,int high,int b[])
{//用分治法对R[low..high]进行二路归并排序
   int mid;
   if(low<high){//区间长度大于1
      mid=(low+high)/2; //分解
       MergeSort(a,low,mid ,b); //递归地对R[low..mid]排序
       MergeSort(a,mid+1,b); //递归地对R[mid+1..high]排序
       Merge(a,low,mid,high); //组合,将两个有序区归并为一个有序区
   }
}


接下来让我们看看求逆序对的代码:

#include<bits/stdc++.h>
using namespace std;
long long count1=0;//为了防止溢出,count用long long 定义
void merge(int a[],int low,int mid,int high,int b[])//合并
{
    int i=low,j=mid+1,k=0;
    while(i<=mid&&j<=high)    {
        if(a[i]<=a[j]){
            b[k++]=a[i++];            
        }
        else{
            b[k++]=a[j++];
            count1+=mid-i+1;
        }
    }
    while(i<=mid)    {
        b[k++]=a[i++];
    }
    while(j<=high)    {
        b[k++]=a[j++];
    }
    for(int m=0;m<k;m++)
    {
        a[low+m]=b[m];
    }
}
void mergsort(int a[],int first,int last,int b[])//排序
{
    int mid;
    if(first<last)
    {
        mid=(first+last)/2;
        mergsort(a,first,mid,b);
        mergsort(a,mid+1,last,b);
        merge(a,first,mid,last,b);
    }
}
int main()
{
    int n;
    cin>>n;
    int a[n],b[n];
    for(int i=0;i<n;i++)
    {
        cin>>a[i];
    }
    mergsort(a,0,n-1,b);
    cout<<count1<<endl;
    return 0;
}




两者的差别在于多了一个计数器count1。
如果左数组比右数组大,那么是逆序对,由于左右数组是有序的(从小到大),当左数组中M比右数组中N大,那么M左边的数也比右数组中的N大。所以count1=count1+mid-i+1.

伪原创。

归并排序是一种经典的排序算法,它通过将待排序的序列递归地划分成较小的子序列,然后将这些子序列进行合并,最终得到一个有序的序列。在归并排序的过程中,可以通过统计逆序对的数量来评估序列的有序程度。 使用归并排序逆序对的基本思想是:在合并两个有序子序列的过程中,如果左子序列中的元素大于右子序列中的元素,则构成了一个逆序对。在合并过程中,统计逆序对的数量,并将两个子序列合并成一个有序序列。 具体步骤如下: 1. 将待排序序列不断二分,直到每个子序列只有一个元素。 2. 逐层合并相邻的子序列,并在合并过程中统计逆序对的数量。 3. 重复步骤2,直到所有子序列合并成一个有序序列。 以下是使用归并排序逆序对的示例代码: ```python def merge_sort(arr): if len(arr) <= 1: return arr, 0 mid = len(arr) // 2 left, count_left = merge_sort(arr[:mid]) right, count_right = merge_sort(arr[mid:]) merged, count_merge = merge(left, right) return merged, count_left + count_right + count_merge def merge(left, right): merged = [] count = 0 i, j = 0, 0 while i < len(left) and j < len(right): if left[i] <= right[j]: merged.append(left[i]) i += 1 else: merged.append(right[j]) j += 1 count += len(left) - i merged.extend(left[i:]) merged.extend(right[j:]) return merged, count ``` 使用上述代码,可以通过调用`merge_sort`函数来求解给定序列的逆序对数量。函数返回排序后的序列以及逆序对的数量。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值