1.动画展示

归并.gif

2.思路分析

归并排序就是递归得将原始数组递归对半分隔,直到不能再分(只剩下一个元素)后,开始从最小的数组向上归并排序
1. 向上归并排序的时候,需要一个暂存数组用来排序,
2. 将待合并的两个数组,从第一位开始比较,小的放到暂存数组,指针向后移,
3. 直到一个数组空,这时,不用判断哪个数组空了,直接将两个数组剩下的元素追加到暂存数组里,
4. 再将暂存数组排序后的元素放到原数组里,两个数组合成一个,这一趟结束。

根据思路分析,每一趟的执行流程如下图所示:
5.归并排序(Merge Sort) - 图2
image.png
image.png
image.png

3.复杂度分析

1. 时间复杂度:递归算法的时间复杂度公式:T[n] = aT[n/b] + f(n) **

5.归并排序(Merge Sort) - 图6
无论原始数组是否是有序的,都要递归分隔并向上归并排序,所以时间复杂度始终是O(nlog2n)
2. 空间复杂度:
每次两个数组进行归并排序的时候,都会利用一个长度为n的数组作为辅助数组用于保存合并序列,所以空间复杂度为O(n)。

4.代码实现

  1. public class MergeSort {
  2. public static void main(String[] args) {
  3. int arr[] = { 8, 4, 5, 7, 1, 3, 6, 2 };
  4. System.out.println("归并排序前:"+Arrays.toString(arr));
  5. int[] temp = new int[arr.length];
  6. mergeSort(arr,0,arr.length-1,temp);
  7. System.out.println("归并排序后:"+Arrays.toString(arr));
  8. }
  9. //分+合方法
  10. public static void mergeSort(int[] arr, int left, int right, int[] temp){
  11. if (left<right){
  12. int mid = (right+left)/2;
  13. //向左递归进行分解
  14. mergeSort(arr,left,mid,temp);
  15. //向右递归进行分解
  16. mergeSort(arr,mid+1,right,temp);
  17. //合并
  18. merge(arr, left, mid, right, temp);
  19. }
  20. }
  21. //合并的方法
  22. /**
  23. *
  24. * @param arr 排序的原始数组
  25. * @param left 左边有序序列的初始索引
  26. * @param mid 中间索引
  27. * @param right 右边索引
  28. * @param temp 做中转的数组
  29. */
  30. public static void merge(int[] arr, int left, int mid, int right, int[] temp){ //合并了7次
  31. int i = left; // 初始化i, 左边有序序列的初始索引
  32. int j = mid + 1; //初始化j, 右边有序序列的初始索引
  33. int t = 0; // 指向temp数组的当前索引
  34. //(一)
  35. //先把左右两边(有序)的数据按照规则填充到temp数组
  36. //直到左右两边的有序序列,有一边处理完毕为止
  37. while (i<=mid && j<=right){
  38. //如果左边的有序序列的当前元素,小于等于右边有序序列的当前元素
  39. //即将左边的当前元素,填充到 temp数组
  40. if (arr[i] <= arr[j]){
  41. temp[t] = arr[i];
  42. t += 1;
  43. i += 1;
  44. }else {//反之,将右边有序序列的当前元素,填充到temp数组
  45. temp[t] = arr[j];
  46. t += 1;
  47. j += 1;
  48. }
  49. }
  50. //(二)
  51. //把有剩余数据的一边的数据依次全部填充到temp
  52. while (i <= mid){//左边的有序序列还有剩余的元素,就全部填充到temp
  53. temp[t] = arr[i];
  54. t += 1;
  55. i += 1;
  56. }
  57. while (j<=right){//右边的有序序列还有剩余的元素,就全部填充到temp
  58. temp[t] = arr[j];
  59. t += 1;
  60. j += 1;
  61. }
  62. //将temp数组的元素拷贝到arr
  63. //注意,并不是每次都拷贝所有
  64. t = 0;
  65. // int tempLeft = left;
  66. System.out.println("合并,"+"left:"+left+";right:"+right);
  67. while(left <= right){
  68. arr[left] = temp[t];
  69. t += 1;
  70. left += 1;
  71. }
  72. }
  73. }

运行结果

  1. 归并排序前:[8, 4, 5, 7, 1, 3, 6, 2]
  2. 合并,left:0;right:1 //索引,说明合并了7次,每次合并后的数组都是有序的
  3. 合并,left:2;right:3
  4. 合并,left:0;right:3
  5. 合并,left:4;right:5
  6. 合并,left:6;right:7
  7. 合并,left:4;right:7
  8. 合并,left:0;right:7
  9. 归并排序后:[1, 2, 3, 4, 5, 6, 7, 8]
  10. Process finished with exit code 0