并归排序法求逆序数

逆序对(inversion pair)是指在序列{a0,a1,a2...an}中,若ai<aj(i>j),则(ai,aj)上一对逆序对。而逆序数 (inversion number)顾名思义就是序列中逆序对的个数。例如: 1 2 3是顺序,则逆序数是0;1 3 2中(2,3)满足逆序对的条件,所以逆序数只有1; 3 2 1中(1,2)(1,3)(2,3)满足逆序对,所以逆序是3。由定义不难想象,序列n的逆序数范围在[0,n*(n-1)/2],其中顺序时逆序数为 0,完全逆序时逆序数是n*(n-1)/2。
就我所知,目前求这种逆序对最快的算法是利用归并排序,其时间复杂度为O(nlgn), 空间复杂度为O(n)。

代码如下:#include <iostream> #include <cstring> using namespace std; long c[500005]; long a[500005]; long b[500005]; long long num=0; const long MAX=1000000000; void merge(int s,int p,int e) { memcpy(a,c+s,sizeof(long)*(p-s+1)); memcpy(b,c+p+1,sizeof(long)*(e-p)); int l1 = p-s+1; int l2 = e-p; a[l1] = b[l2] = MAX;//在比较过程中设置尾部哨兵 int i =0; int j = 0; int k =0; /* while(i<l1 && j<l2) { if(a[i]<b[j]) { c[k++] = a[i]; i++; } else if(a[i]>b[j]) { c[k++]=b[j]; j++; } else { c[k++]=a[i]; i++; j++; } } */ //a[i]表示前半部分 //b[i]表示后半部分 //逆序数的表现位: //i<j && v[i]>v[j] for(k=s;k<=e;k++) { if(a[i]<=b[j]) { c[k]=a[i]; i++; } else { c[k]=b[j]; j++; num+=l1-i; /* 此时就表现出了逆序数的特征,因为a[i]>b[j],并且a和b中数据都有序,所以a[i+1,...,l1]>b[j],故num增加l1-i。 比如a={4,7,9,MAX} b={5,6,8,MAX} 当i=1时,a[i]=7,此时a[i]>b[j]=5,并且a[i+1]=9>b[j],此时num增加l1-i=2; */ } } } void merge_sort(int s,int e) { if(s<e) { int p = (e+s)/2; merge_sort(s,p); merge_sort(p+1,e); merge(s,p,e); } } int main() { int n ; int i = 0; cin>>n; while(n!=0) { i = 0; memset(a,0,sizeof(0)); memset(b,0,sizeof(0)); memset(c,0,sizeof(0)); num=0; for(i=0;i<n;i++) cin>>c[i]; merge_sort(0,n-1); cout<<num<<endl; cin>>n; } }

 

你可能感兴趣的:(并归排序法求逆序数)