归并排序
归并排序其实就是一个不断二分和两个有序数组合并成一个有序数组的过程。所以时间复杂度为二分的log和每次进行遍历合并的n组成,也就是O(nlogn)
逻辑部分建议查看视频归并排序算法讲解,然后直接进入代码看实现,参考归并排序(Java代码实现)。实在难理解建议debug一步步进行。
在代码上也是分为两个部分,第一个是不断二分,然后将二分后的两个组进行合并排序。合并排序的过程就是常规比较。是不断比较两个数组的首个数字比大小,小的就先放入临时数组,然后指针向后移动,不断进行比较。如果最后一个数组还有剩余,就直接进行誊写到临时数组中。最后将临时数组中的数据誊写到原数组中,改变原数组的值。
其中tmp数组使用来临时存放排序后的数组的,合并后需要重新誊写到原数组arr中。
在下面的代码中实现。
public static void mergeSort(int[] arr,int low,int high,int[] tmp){
if(low<high){
int mid=(high+low)/2;
mergeSort(arr,low,mid,tmp);//左部分进行排序
mergeSort(arr,mid+1,high,tmp);//右部分进行排序
merge(arr,low,mid,high,tmp);//两部分进行合并排序
}
}
下面是两部分进行合并,比较容易理解。重要的是要将临时数组的数据誊写到原数组的对应位置,因为下一次还需要根据索引进行比较。
public static void merge(int[] arr,int low,int mid,int high,int[] tmp){
int i=low;
int j=mid+1;
int u=0;
while(i<=mid&&j<=high){
if(arr[i]<arr[j]){
tmp[u]=arr[i];
i=i+1;
u=u+1;
}else{
tmp[u]=arr[j];
j=j+1;
u=u+1;
}
}
while(i<=mid){
tmp[u]=arr[i];
i=i+1;
u=u+1;
}
while(j<=high){
tmp[u]=arr[j];
j=j+1;
u=u+1;
}
for(int o=0;o<u;o++){
arr[low+o]=tmp[o];
}
}
不用担心打开tmp的线程不安全,因为其实并不会同时使用tmp,这是一个线性的操作,看例子。一个归并排序在代码中运行实现的全部过程。
//归并排序
/*
例子:arr={1,3,2,4,5}数组进行归并排序
int[] tmp=new int[arr.length]
进入mergeSort函数然后(0+4)/2=2,low=0,mid=2,high=4,左边数组首先进行排序
进入左排序1:mergeSort(arr,0,2,tmp)
然后又执行(0+2)/2=1。mid=1,low=0,high=2;
进行左排序2:mergeSort(arr,0,1,tmp)
然后又进入mergeSort函数,判断1>0,执行(1+0)/2=0,
进入左排序3:mergeSort(arr,0,0,tmp)
此时0=0,所以跳出函数,也就是进行了单一元素的排序,这是
跳出左排序3:mergeSort(arr,0,0,tmp)
而这个函数执行时代表了low=0,mid=0,high=1,所以接下俩执行右边的排序,
进入右排序3:mergeSort(arr,1,1,tmp),1=1,所以
跳出右排序3:mergeSort(arr,1,1,tmp)
相当于对第二个元素进行了排序,最后执行merge函数,,mid=0,low=0,high=1,将两部分进行合并排序,执行完后此时跳出
跳出左排序2:mergeSort(arr,0,1,tmp)
进入右排序2:mergeSort(arr,2,2,tmp),2=2
跳出右排序2:mergeSort(arr,2,2,tmp)
执行merge函数,mid=0,low=1,high=2,,将索引0,1,2进行排序
进入右排序1:mergeSort(arr,3,4,tmp),3<4
进入左排序2:mergeSort(arr,3,3,tmp),3=3
跳出左排序2:mergeSort(arr,3,3,tmp)
进入右排序2:mergeSort(arr,4,4,tmp),4=4
跳出右排序2:mergeSort(arr,4,4,tmp)
最后执行merge函数,将两部分进行合并排序,mid=3,low=3,high=4,将索引3,4进行排序
跳出右排序1:mergeSort(arr,3,4,tmp)
最后执行merge函数,mid=2,low=0,high=4,将0,1,2和3,4进行合并,也就是输出最终答案。
over
*/
运行代码及运行结果
public static void main(String[]args){
int[] arr = {11,44,23,67,88,65,34,48,9,12};
int[] tmp = new int[arr.length]; //新建一个临时数组存放
mergeSort(arr,0,arr.length-1,tmp);
for(int i=0;i<arr.length;i++){
System.out.print(arr[i]+" ");
}
}
9 11 12 23 34 44 48 65 67 88
Process finished with exit code 0