归并排序通过分治的思想可以在nlogn的时间内完成数组的排序
同时在归并排序的归并过程中,又可以通过排序内部的细节获得原数组的逆序数,见注释
直接上代码了:
void merge(int a[],int start,int len,int size) { int l=0,r=0; int mid=start+len/2; int lsize=min(len/2+len%2,size-start); //左边集合的个数 int rsize=min(len,size-start)-lsize; //右边集合的个数 int *al=(int *)malloc(sizeof(int)*(lsize)); int *ar=(int *)malloc(sizeof(int)*(rsize)); for(int i=start;i<start+lsize;i++) { al[i-start]=a[i]; } for(int i=start+lsize;i<start+lsize+rsize;i++) { ar[i-start-lsize]=a[i]; } int k=0; for(k=0;l<lsize&&r<rsize;k++) { if(al[l]<=ar[r]) { a[start+k]=al[l]; l++; } else { a[start+k]=ar[r]; ans+=lsize-l; //此时左边集合还有lsize-l个数没有放,则意味着对于右边集合的第一个数,前面有lsize-l个数比它还要大,故逆序数加上lsize-l r++; } } if(k<lsize+rsize) { if(l<lsize) { for(int i=l;i<lsize;i++) { a[start+k]=al[i]; k++; } } else { for(int i=r;i<rsize;i++) { a[start+k]=ar[i]; k++; } } } free(ar); free(al); } void mergesort(int a[],int size) { for(int len=2;len<size*2;len*=2) { for(int i=0;i<size;i+=len) { merge(a,i,len,size); } } }