在归并排序算法中稍作修改,就可以在nlog2(n)的时间内求逆序对。
将数组A[1...size],划分为A[1...mid] 和 A[mid+1...size].那么逆序对数的个数为 f(1, size) = f(1, mid) + f(mid+1, size) + s(1, mid, size),这里s(1, mid, size)代表左值在[1---mid]中,右值在[mid+1, size]中的逆序对数。由于两个子序列本身都已经排序,所以查找起来非常方便。对于序列前半部分中的某个数a[i],序列后半部分中的某个数a[j],如果a[i]<=a[j]没有逆序数,如果a[i]>a[j],那么逆序数为a[i]后边元素的个数(包括a[i]),即mid-i+1,这样累加每次递归过程的逆序数,在完成整个递归过程之后,最后的累加和就是逆序的总数.
#include<iostream> using namespace std; void merge(int a[], int b[], int start, int mid, int end, int& inc) { int i = start; int j = mid+1; int k = start; while( i <= mid && j <= end ) { if ( a[i] <= a[j] ) { b[k++] = a[i++]; } else { b[k++] = a[j++]; inc+=mid-i+1; //求逆序对 } } while( i <= mid ) b[k++] = a[i++]; while( j <= end ) b[k++] = a[j++]; for( int n = 0; n < end - start + 1; n++ ) { a[start++] = b[n]; } } void msort(int a[], int b[], int start, int end, int& inc) { if ( start == end ) return; if( start < end ) { int mid = (start+end)/2; msort(a, b, start, mid, inc); msort(a, b, mid+1, end, inc); merge(a, b, start, mid, end, inc); } } void mergeSort(int a[], int n, int& inc) { int *b = new int[n]; msort(a, b, 0, n-1, inc); } int main() { int a[] = {5, 4, 3 }; int n = sizeof(a)/sizeof(int); int inc = 0; mergeSort(a, n, inc); cout<<inc<<endl; return 0; }