归并排序与逆序对

算法导论上2-4是这样一个题目:

设A[1...n]是一个包含n个不同数的数组。如果在i<j的情况下,有A[i]>A[j],则(i, j)就称为A中的一个逆序对(inversion)。试给出一个算法,它能用O(nlgn)的最坏情况运行时间确定n个元素的任何排列中逆序对的数目。

咋一看没有什么思路,可一看见提示赫然给出:修改归并排序,于是顿悟。其实,只需要在归并排序中加上一个计数器,在每次merge的时候计算逆序对,这样就可以算出总共的逆序对了。

#include <iostream>
using namespace std;
void merge_sort(int *A,int p, int r);
void merge(int *A,int p, int q, int r);
const int max_int = 0x7fffffff;
int sum = 0;
int main()
{
// int a[]={
// 82,91,14,91,64,11,29,55,96,97,17,97,96,49,80
//
//,15,43,92,79,96,66, 5,85,93,68,76,75,40,66,18
//
//,71, 4,28, 6,11,83,70,32,95, 4,44,39,77,80,20
//
//,49,45,65,71,76,28,68,66,17,13,50,96,35,59,23
//
//,75,26,51,70,89,96,55,15,16,26,84,26,82,25,93
//
//,36,20,26,62,48,36,83,59,55,92,29,76,76,39,57
//
//, 9, 6,54,78,93,14,57,47, 2,34} ;
int a[]={7,3,2,5,1,4,5,9,100,1};
int i;
int length = sizeof(a)/sizeof(int);
for(i=0;i<length;++i)
cout<<a[i]<<(i%10==9?'\n':' ');
merge_sort(a,0,length-1);
cout<<"\nafter merge_sort: \n";
for(i=0;i<length;++i)
cout<<a[i]<<(i%10==9?'\n':' ');
cout<<"total number of iversion is: "<<sum<<endl;
}
void merge_sort(int *A,int p, int r)
{
int q;
if(p < r)
{
q = (p + r)/2;
merge_sort(A,p,q);
merge_sort(A,q+1,r);
merge(A,p,q,r);
}
}
void merge(int *A,int p, int q, int r)
{
int n1 = q-p+1;
int n2 = r-q;
int *L = new int[n1+1];
int *R = new int[n2+1];
int i,j,k;
for(i=0;i<n1;++i)
L[i] = A[p+i];
for(j=0;j<n2;++j)
R[j] = A[q+j+1];
L[n1] = max_int;
R[n2] = max_int;
i=0;j=0;
for(k=p;k<=r;++k)
{
if(L[i]<=R[j])
A[k]=L[i++];
else
{
A[k]=R[j++];
sum+=n1-i;
}
}
}

再上网搜,发现这种方法已经被无数人研习过,poj2299就是一道典型的求逆序对的题。于是蒻人欣欣然修改代码submit等待AC,结果出现memory limited exceeded。观察数据规模和自己的代码,需要进行若干处修改:

  • sum得用64位整型:long long;
  • 各个数组在全局申请,不要动态申请,也不要在main函数中申请;
原文地址:https://www.cnblogs.com/bovine/p/2185006.html