一:归并排序算法实现
直接看图:
简单说:
一个数组分成两个数组,让两个子数组有序,将有序的两个子数组合并,怎么让子数组有序?依靠归并算法
归并算法
注意:传入的子数组是有序的.怎么得到有序的数组,子数组一直划分下去,子数组迟早是一个元素,一个元素的数组当然有序,然后合并,合并过程让两个有序的子数组变成一个有序的子数组,然后一直返回,直到让这个数组有序
public static void merge(int[] arr,int L,int mid,int R){
//用help数组去复制
int[] help=new int[R-L+1];
int leftPtr=L;
int rightPtr=mid+1;
int i=0;
//这里必须等于也复制左数组的元素,保持元素稳定性
while(leftPtr<=mid&&rightPtr<=R) help[i++]=arr[leftPtr]<=arr[rightPtr]?arr[leftPtr++]:arr[rightPtr++];
while(leftPtr<=mid) help[i++]=arr[leftPtr++];
while(rightPtr<=R) help[i++]=arr[rightPtr++];
//把合并的数组复制会原数组对应的下标中;
for (int j = 0; j < help.length; j++) {
//注意:arr对应的下标是L+j;
arr[L+j]=help[j];
}
}
递归实现
public static void sort(int[] arr,int L,int R){//传递数组,分割成子数组,然后合并(合并过程就是排序的过程)
if(L==R) return;//思考边界的情况,不可能出现L>R;
//分割:
int mid=L+(R-L)/2;
sort(arr,L,mid);
sort(arr,mid+1,R);
//排序好子数组后,来合并两个子数组
merge(arr,L,mid,R);
}
非递归实现
它是从递归的最底层到上层通过一次一次循环模拟的
public static void sort2(int[] arr){
if(arr==null||arr.length<2) return;
int len=arr.length;
int mergeSize=1;//递归就是从子数组为1开始merge的....
while(mergeSize<len){//每次更换一次mergeSize去迭代一遍数组
int L=0;
while(L<len){//以本mergeSize去迭代一遍
if(mergeSize>=len-L) break;//剩下的长度不能分配一个子数组了
int mid=L+mergeSize-1;//左数组的最后一个元素
int R=mid+Math.min(len-mid-1,mergeSize);//R正常情况是mergeSize大小,不够就是剩下的大小len-mid-1
merge(arr,L,mid,R);
L=R+1;
}
//更新mergeSize
if(mergeSize>len/2) break;//因为*2后会大于len的,此时mergeSize可能越界
mergeSize=mergeSize<<1;
}
}
二:归并算法深度实践
思想:每次归并的时候,其实左右数组之间的数是会比较大小的
算法题
在一个数组中,一个数左边比它小的数的总和,叫该数的小和
所有数的小和累加起来,叫数组小和
给定一个数组arr,求数组小和
方法:利用归并时候比较过程,在比较左右子数组时机顺便我们最小和求出
代码:
public class SmallSum {
public static void main(String[] args) {
int[] arr={1,8,2,6,1,2,3,4,5,6,7};
System.out.println(sort(arr, 0, arr.length - 1));
}
public static int sort(int[] arr, int L , int R){
if(L==R){
return 0;
}
int mid=L+(R-L)/2;
//(合并过程,只有右数组的元素为基准,去观察左数组有没有小于它的元素,它不会找和自己一个数组中找,我们的规则是合并了一个数组,最小和就产生了)
return sort(arr,L,mid)+
sort(arr,mid+1,R)+
merge(arr,L,mid,R);
}
//每merge一次,就会产生一次最小和
public static int merge(int[] arr,int L,int mid,int R){
int result=0;
int[] help=new int[R-L+1];
int i=0;
int lPtr=L;
int rPtr=mid+1;
while(lPtr<=mid&&rPtr<=R){
result+=arr[lPtr]>arr[rPtr]?(mid-lPtr+1):0;//将序对的个数
help[i++]=arr[lPtr]<=arr[rPtr]?arr[lPtr++]:arr[rPtr++];
}
while(lPtr<=mid) help[i++]=arr[lPtr++];
while(rPtr<=R) help[i++]=arr[rPtr++];
for (int j = 0; j < help.length; j++) {
arr[L+j]=help[j];
}
return result;
}
}