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

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

对于一个包含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
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值