归并排序算法详解(递归处理)
基本思想
从名字可以看到,归并排序算法,何为归并?就是把小的部分归并成大的部分。因此归并排序算法其实采用了分治的策略,也就是把一个问题分成若干个小的方便处理的问题,最后再把这些小问题得到的答案合并起来,得到最终的答案。 我们常见的归并排序算法其实是二分归并排序,也就是我们把一个数组序列分为左右两部分(每一部分会继续划分左右两部分),然后对这两部分分别进行排序,左右排序完成后,再将这两部分合并起来,简化排序的过程。 具体的细节我建议大家去看代码中的逻辑,跟着代码走一遍,会理解的更加清楚,话不多说上代码
一、代码示例
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)
尾注
下一篇:
数据结构 线性表试题