基本思想
从名字可以看到,归并排序算法,何为归并?就是把小的部分归并成大的部分。因此归并排序算法其实采用了分治的策略,也就是把一个问题分成若干个小的方便处理的问题,最后再把这些小问题得到的答案合并起来,得到最终的答案。
我们常见的归并排序算法其实是二分归并排序,也就是我们把一个数组序列分为左右两部分(每一部分会继续划分左右两部分),然后对这两部分分别进行排序,左右排序完成后,再将这两部分合并起来,简化排序的过程。
具体的细节我建议大家去看代码中的逻辑,跟着代码走一遍,会理解的更加清楚,话不多说上代码
一、代码示例
import java.util.Arrays;
import java.util.Random;
/**
* 归并排序算法
*/
public class MergeSort {
public static void mergeSort(int[] arr){
if(arr ==null ||arr.length<2){
return ;
}
process(arr,0,arr.length-1);
}
public static void process(int[] arr,int left,int right){
int mid = left+((right - left) >> 1);
if (left == right){
return;
}
process(arr,left,mid);
process(arr,mid+1,right);
Merge(arr,left,mid,right);
}
public static void Merge(int[] arr, int left, int mid, int right) {
int p1 = left;
int p2 = mid+1;
int []help = new int[right - left +1];
int i = 0;
//对比左右两部分的值,进行有序排列
while(p1<=mid && p2<=right){
help[i++] = arr[p1]<arr[p2]?arr[p1++]:arr[p2++];
}
while (p1<=mid){
help[i++] = arr[p1++];
}
while (p2<=right){
help[i++] = arr[p2++];
}
for (int j = 0;j<help.length;j++) {
arr[left+j] = help[j];
}
}
/**
* 随机生成数组序列
* @param maxSize 序列最大长度
* @param maxValue 序列最大值
* @return
*/
public static int[] generateRandomArray(int maxSize,int maxValue){
Random random = new Random();
int[] arr = new int[(int) random.nextInt(maxSize+1)];
for(int i = 0;i<arr.length;i++){
arr[i] = random.nextInt(maxValue + 1);
}
return arr;
}
public static void main(String[] args) {
int[] arr = generateRandomArray(10,10);
System.out.println(Arrays.toString(arr));
mergeSort(arr);
System.out.println(Arrays.toString(arr));
}
}
细节
上面代码中求中值时没有用int mid = (left + right)/ 2,是因为当数值很大时,left + right的值会溢出,这其实是一个小bug,这里我们采用减法的形式,不会造成溢出的情况,此外,使用>>这种二进制运算的形式也可以加快代码的运行速度。
二、复杂度分析
因为这里我们采用了递归的形式进行计算,并且它的复杂度符合master公式:
在上述公式中,a是递归过程中的子递归的个数,N/b是每一部分子递归的数据规模,d是除了子递归外的剩余操作步数。
很明显,在二分归并排序算法中,a= 2,b=2,d=1,因此它的时间复杂度O(N * log(n))
空间复杂度:在Merge函数中,我们创建了一个临时数组,因此空间复杂度为O(n)
尾注
留下笔记,只为方便回忆,如有侵权,还请联系,如有错误,恳请纠正。陆续更新,还请关注。