题目:设A[1…n]是一个包含n个不同数的数组。如果在i < j 的情况下,有 A[i]>A[j],则(i,j)就称为A中的一个逆序对(inversion)。
c.插入排序的运行时间与各个元素的逆序对总和相等。
d.给出一个算法,它能用Θ(nlgn)的最坏情况运行时间,确定 n 个元素的任何排列中逆序对的数目。
为了验证程序的正确性,我顺便写了一个暴力求解的算法,Java代码如下:
/**
* 暴力求解逆序对方法
* @param a
*/
public static void violence_inversions( int[] a ) {
for (int i = 0; i < a.length; i++) {
int key = a[i];
int j = i + 1;
while ( j < a.length ) {
if ( key > a[j] )
inversions++;
j++;
}
}
}
下面是Θ(nlgn)的算法,通过对归并排序的修改。
Java代码如下:
package hanxl.insist.twochapter;
public class Exercise_2_4 {
private static int inversions = 0;
public static void main(String[] args) {
//测试数组
int[] exmp = { 2,34,890,23, 45, 12, 56, 32, 78, 1, 3, 90, 678 };
countInversions(exmp, 0, exmp.length);
System.out.println(inversions); //32
}
private static int countInversions(int[] arr, int lo, int hi) {
inversions = 0;
if ( lo < hi - 1 ) {
int mi = ( lo + hi ) / 2;
inversions += countInversions( arr, lo, mi );
inversions += countInversions( arr, mi, hi );
inversions += mergeInversions( arr, lo, mi, hi);
}
return inversions;
}
private static int mergeInversions(int[] arr, int lo, int mi, int hi) {
int frontLength = mi - lo;
int backLength = hi - mi;
int[] l = new int[frontLength];
int[] r = new int[backLength];
for (int i = 0; i < frontLength; i++)
l[i] = arr[lo + i];
for (int i = 0; i < backLength; i++)
r[i] = arr[mi + i];
int lp = 0;
int rp = 0;
boolean counted = false;
inversions = 0;
for (int i = lo; i < hi; i++) {
if (lp == frontLength)
break;
if (rp == backLength) {
arr[i] = l[lp];
lp++;
continue;
}
if ( !counted && l[lp] > r[rp] ) {
inversions += frontLength - lp;
counted = true;
}
if (l[lp] < r[rp]) {
arr[i] = l[lp];
lp++;
} else {
arr[i] = r[rp];
rp++;
counted = false;
}
}
return inversions;
}
}
mergeInversions过程我并没有使用哨兵。