归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题(divide) 成一些小的问题然后递归求解,而治 (conquer)的阶段则将分的阶段得到的各答案 “修补” 在一起,即分而治之)。

    分而治之

    图解排序算法(四)之归并排序 - dreamcatcher-cx - 博客园 - 图1

    可以看到这种结构很像一棵完全二叉树,本文的归并排序我们采用递归去实现(也可采用迭代的方式去实现)。阶段可以理解为就是递归拆分子序列的过程,递归深度为 log2n。

    再来看看阶段,我们需要将两个已经有序的子序列合并成一个有序序列,比如上图中的最后一次合并,要将[4,5,7,8]和[1,2,3,6]两个已经有序的子序列,合并为最终序列[1,2,3,4,5,6,7,8],来看下实现步骤。

    图解排序算法(四)之归并排序 - dreamcatcher-cx - 博客园 - 图2

    图解排序算法(四)之归并排序 - dreamcatcher-cx - 博客园 - 图3

    图解排序算法(四)之归并排序 - dreamcatcher-cx - 博客园 - 图4

    package sortdemo; import java.util.Arrays; /* Created by chengxiao on 2016/12/8. */
    public class MergeSort { public static void main(String []args){ int []arr = {9,8,7,6,5,4,3,2,1};
    sort(arr);
    System.out.println(Arrays.toString(arr));
    } public static void sort(int []arr){ int []temp = new int[arr.length];// 在排序前,先建好一个长度等于原数组长度的临时数组,避免递归中频繁开辟空间
    sort(arr,0,arr.length-1,temp);
    } private static void sort(int[] arr,int left,int right,int []temp){if(leftsort(arr,left,mid,temp);// 左边归并排序,使得左子序列有序
    sort(arr,mid+1,right,temp);// 右边归并排序,使得右子序列有序
    merge(arr,left,mid,right,temp);// 将两个有序子数组合并操作
    }
    } private static void merge(int[] arr,int left,int mid,int right,int[] temp){ int i = left;// 左序列指针
    int j = mid+1;// 右序列指针
    int t = 0;// 临时数组指针
    while (i<=mid && j<=right){ if(arr[i]<=arr[j]){
    temp[t++] = arr[i++];
    }else {
    temp[t++] = arr[j++];
    }
    } while(i<=mid){// 将左边剩余元素填充进 temp 中
    temp[t++] = arr[i++];
    } while(j<=right){// 将右序列剩余元素填充进 temp 中
    temp[t++] = arr[j++];
    }
    t \= 0; // 将 temp 中的元素全部拷贝到原数组中
    while(left <= right){
    arr[left++] = temp[t++];
    }
    }
    }

    图解排序算法(四)之归并排序 - dreamcatcher-cx - 博客园 - 图5

    执行结果

    [1, 2, 3, 4, 5, 6, 7, 8, 9]

    归并排序是稳定排序,它也是一种十分高效的排序,能利用完全二叉树特性的排序一般性能都不会太差。java 中 Arrays.sort() 采用了一种名为 TimSort 的排序算法,就是归并排序的优化版本。从上文的图中可看出,每次合并操作的平均时间复杂度为 O(n),而完全二叉树的深度为 | log2n|。总的平均时间复杂度为 O(nlogn)。而且,归并排序的最好,最坏,平均时间复杂度均为 O(nlogn)。
    https://www.cnblogs.com/chengxiao/p/6194356.html

    1. import java.util.*;
    2. public class Main {
    3. public static int mergeSort(int[] array, int left, int right) {
    4. if (right - left <= 0) {
    5. // 不能再分
    6. return 0;
    7. } else {
    8. int mid = (left + right) / 2;
    9. // 不停的进行划分
    10. int count = mergeSort(array, left, mid) + mergeSort(array, mid + 1, right);
    11. // 用来保存数据的临时数组
    12. ArrayList<Integer> temp = new ArrayList<>();
    13. // 前半部分的指针
    14. int i = left;
    15. // 后半部分的指针
    16. int j = mid + 1;
    17. // 开始比较,直到一个指针达到边界
    18. while (i <= mid && j <= right) {
    19. if (array[i] <= array[j]) {
    20. temp.add(array[i]);
    21. i++;
    22. } else {
    23. count += mid - i + 1;
    24. temp.add(array[j]);
    25. j++;
    26. }
    27. }
    28. while (i <= mid) {
    29. temp.add(array[i++]);
    30. }
    31. while (j <= right) {
    32. temp.add(array[j++]);
    33. }
    34. for (int k = 0; k < right - left + 1; k++) {
    35. array[left + k] = temp.get(k);
    36. }
    37. return count;
    38. }
    39. }
    40. public static void main(String[] args) {
    41. Scanner scan = new Scanner(System.in);
    42. int num = scan.nextInt();
    43. while (num > 0) {
    44. int length = scan.nextInt();
    45. int[] array = new int[length];
    46. for (int i = 0; i < length; i++) {
    47. array[i] = scan.nextInt();
    48. }
    49. int result = mergeSort(array, 0, length - 1);
    50. System.out.println(result);
    51. num--;
    52. }
    53. }
    54. }