1.归并排序代码先贴 上
1 public static void merge_sort(int[] A, int l, int r){ 2 int m = (l + r)/2; 3 if(l == r) 4 return; 5 merge_sort(A,l,m); 6 merge_sort(A,m+1,r); 7 merge(A,l,m,r); 8 } 9 10 public static void merge(int [] A, int l, int m, int r){ 11 int [] help = new int [r - l + 1]; 12 int i = l, j = m+1,k = 0; 13 while(i <= m && j <= r){ 14 help[k++] = A[i] < A[j]? A[i]:A[j]; 15 i = A[i] < A[j]? i + 1: i; 16 j = A[i] < A[j]? j : j + 1; 17 } 18 19 while(i <= m){ 20 help[k++] = A[i++]; 21 } 22 while(j <= r){ 23 help[k++] = A[j++]; 24 } 25 for (int n = l; n <= r; n++) { 26 A[n] = help[n-l]; 27 } 28 }
时间复杂度 O(nlogn)
2。应用
主要是小和问题和逆序对问题,还有其他一些变形。只要是看到一些左右相互比较,左边比右边大。。。。都可以往归并上思考
a.小和问题
在一个数组中,每一个数左边比当前数小的数累加起来,叫做这个数组的小和。求一个数组
的小和。
例子:
[1,3,4,2,5]
1左边比1小的数,没有;
3左边比3小的数,1;
4左边比4小的数,1、3;
2左边比2小的数,1;
5左边比5小的数,1、3、4、2;
所以小和为1+1+3+1+1+3+4+2=16
1 package chuji; 2 3 import java.util.*; 4 /* 5 小和问题 6 在一个数组中,每一个数左边比当前数小的数累加起来,叫做这个数组的小和。求一个数组 7 的小和。 8 例子: 9 [1,3,4,2,5] 10 1左边比1小的数,没有; 11 3左边比3小的数,1; 12 4左边比4小的数,1、3; 13 2左边比2小的数,1; 14 5左边比5小的数,1、3、4、2; 15 所以小和为1+1+3+1+1+3+4+2=16 16 */ 17 public class xiaohe { 18 public static int getX(int [] A){ 19 return merge_sort(A,0,A.length-1); 20 } 21 22 public static int merge_sort(int [] A,int l,int r){ 23 if(l >= r) 24 return 0; 25 int m = (l + r)/2; 26 return merge_sort(A,l,m) + merge_sort(A,m+1,r) + merge(A,l,m,r); 27 } 28 29 public static int merge(int [] A,int l,int m,int r){ 30 int [] help = new int[r - l +1]; 31 int a = l; 32 int b = m+1; 33 int k = 0; 34 int ans = 0; 35 while(a <= m && b <= r){ 36 help[k++] = A[a] < A[b]? A[a] : A[b]; 37 if(A[a] < A[b]){ 38 ans += A[a] * (r - b + 1); // 在归并排序的基础上就加这句 39 } 40 a = A[a] < A[b] ? a+1:a; 41 b = A[a] < A[b] ? b : b+1; 42 } 43 while(a<=m){ 44 help[k++] = A[a++]; 45 } 46 while(b<m){ 47 help[k++] = A[b++]; 48 } 49 for (int i = 0; i < k; i++) { 50 A[l+i] = help[i]; 51 } 52 return ans; 53 } 54 55 public static void main(String[] args) { 56 int [] A = {1,3,4,2,5}; 57 System.out.println(getX(A)); 58 } 59 }
b.逆序对问题
在一个数组中,左边的数如果比右边的数大,则折两个数构成一个逆序对,请打印所有逆序
对。
1 package chuji; 2 3 import java.util.*; 4 5 /* 6 逆序对问题 7 在一个数组中,左边的数如果比右边的数大,则折两个数构成一个逆序对,请打印所有逆序 8 对。 9 */ 10 11 public class nixudui { 12 public static void printnixu(int [] A){ 13 merge_sort(A,0,A.length-1); 14 } 15 16 public static void merge_sort(int [] A,int l,int r){ 17 if(l >= r) 18 return; 19 int m = (l+r)/2; 20 merge_sort(A,l,m); 21 merge_sort(A,m+1,r); 22 merge(A,l,m,r); 23 } 24 public static void merge(int [] A,int l,int m,int r){ 25 int [] help = new int[r - l + 1]; 26 int x = l; 27 int y = m+1; 28 int k = 0; 29 while(x <= m && y <= r){ 30 31 help[k++] = A[x] < A[y] ? A[x] : A[y]; 32 if(A[x] > A[y]) 33 System.out.println(A[x] + "----" + A[y]); 34 x = A[x] < A[y] ? x+1:x; 35 y = A[x] < A[y] ? y : y+1; 36 } 37 while(x<=m){ 38 help[k++] = A[x++]; 39 if(x<=m){ 40 for (int i = m+1; i <= r; i++) { //左边剩余的话,与右边所有元素形成逆序对 41 System.out.println(A[x] + "----"+ A[i]); 42 } 43 } 44 45 46 } 47 while(y<=r){ 48 help[k++] = A[y++]; 49 } 50 for (int i = 0; i < k; i++) { 51 A[l+i] = help[i]; 52 } 53 54 } 55 56 public static void main(String[] args) { 57 int [] A = {4,3,2,1}; 58 printnixu(A); 59 } 60 }