算法导论第二章 练习题,使用合并排序算法寻找逆序对
基本思想:
在merge过程中,交换位置与一组逆序对是一一对应的。
在左右两个子数组内部是排好序的,所以逆序对的出现仅仅存在于“左数组中的数组大有右数组中的数字”的情况。
所以在每次的merge过程中就可以进行逆序对的计数。
java代码实现
public class InversionCount {
public static void main(String[] args){
int[] arr = new int[]{2,30,19,6,7,3,5};
System.out.println("before sort:");
Sort.printarr(arr);
int num = countinversion(arr,0,arr.length-1);
System.out.println("the number of arr's inversions :"+num);
}
private static int countinversion(int[] arr,int start,int end) {
int count = 0;
if(start<end){
int divide = (end+start)/2;
count+=countinversion(arr,start,divide);
count+=countinversion(arr,divide+1,end);
count+=countmerge(arr,start,end,divide);
}
return count;
}
private static int countmerge(int[] arr, int start, int end, int divide) {
int count = 0;
//三个指针的初始化
int i = 0;
int j = 0;
int k = start;
boolean flag = false;
//创建左右子数组,并赋值
int lsize = divide-start+1;
int rsize = end-divide;
int[] arrL = new int[divide-start+1];
int[] arrR = new int[end-divide];
for(int n =0;n<lsize;n++){
arrL[n] = arr[n+start];
}
for(int n =0;n<rsize;n++){
arrR[n] = arr[n+divide+1];
}
//三个指针移动,进行合并
while(k<end+1){
if(arrL[i]>arrR[j]&&flag==false){
count+=lsize-i;
flag = true;
}
if(arrL[i]<arrR[j]){
arr[k]=arrL[i];
k++;
i++;
if(i>=lsize)
break;
}else{
arr[k]=arrR[j];
k++;
j++;
flag = false;
if(j>=rsize)
break;
}
}
//把剩余的都填进arr
while(i<lsize){
arr[k]=arrL[i];
k++;
i++;
//count++;
}
while(j<rsize){
arr[k]=arrR[j];
k++;
j++;
}
System.out.print(" 本次递归的结果:");
Sort.printarr(arr);
System.out.println(" 本次的计数"+count);
return count;
}
}
运行结果
before sort:
2,30,19,6,7,3,5
本次递归的结果:2,30,19,6,7,3,5
本次的计数0
本次递归的结果:2,30,6,19,7,3,5
本次的计数1
本次递归的结果:2,6,19,30,7,3,5
本次的计数2
本次递归的结果:2,6,19,30,3,7,5
本次的计数1
本次递归的结果:2,6,19,30,3,5,7
本次的计数1
本次递归的结果:2,3,5,6,7,19,30
本次的计数8
the number of arr's inversions :13