利用merge sort寻找逆序对
算法导论第二章 练习题,使用合并排序算法寻找逆序对
基本思想:
- 在merge过程中,交换位置与一组逆序对是一一对应的。
- 在左右两个子数组内部是排好序的,所以逆序对的出现仅仅存在于“左数组中的数组大有右数组中的数字”的情况。 所以在每次的merge过程中就可以进行逆序对的计数。
java代码实现:
1 public class InversionCount { 2 public static void main(String[] args){ 3 int[] arr = new int[]{2,30,19,6,7,3,5}; 4 System.out.println("before sort:"); 5 Sort.printarr(arr); 6 int num = countinversion(arr,0,arr.length-1); 7 System.out.println("the number of arr's inversions :"+num); 8 } 9 10 private static int countinversion(int[] arr,int start,int end) { 11 int count = 0; 12 if(start<end){ 13 int divide = (end+start)/2; 14 count+=countinversion(arr,start,divide); 15 count+=countinversion(arr,divide+1,end); 16 count+=countmerge(arr,start,end,divide); 17 } 18 return count; 19 } 20 21 private static int countmerge(int[] arr, int start, int end, int divide) { 22 int count = 0; 23 //三个指针的初始化 24 int i = 0; 25 int j = 0; 26 int k = start; 27 boolean flag = false; 28 //创建左右子数组,并赋值 29 int lsize = divide-start+1; 30 int rsize = end-divide; 31 int[] arrL = new int[divide-start+1]; 32 int[] arrR = new int[end-divide]; 33 for(int n =0;n<lsize;n++){ 34 arrL[n] = arr[n+start]; 35 } 36 for(int n =0;n<rsize;n++){ 37 arrR[n] = arr[n+divide+1]; 38 } 39 //三个指针移动,进行合并 40 while(k<end+1){ 41 if(arrL[i]>arrR[j]&&flag==false){ 42 count+=lsize-i; 43 flag = true; 44 } 45 if(arrL[i]<arrR[j]){ 46 arr[k]=arrL[i]; 47 k++; 48 i++; 49 if(i>=lsize) 50 break; 51 }else{ 52 arr[k]=arrR[j]; 53 k++; 54 j++; 55 flag = false; 56 if(j>=rsize) 57 break; 58 } 59 } 60 //把剩余的都填进arr 61 while(i<lsize){ 62 arr[k]=arrL[i]; 63 k++; 64 i++; 65 //count++; 66 } 67 while(j<rsize){ 68 arr[k]=arrR[j]; 69 k++; 70 j++; 71 } 72 System.out.print(" 本次递归的结果:"); 73 Sort.printarr(arr); 74 System.out.println(" 本次的计数"+count); 75 return count; 76 } 77 }
运行结果:
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