时间复杂度: O(n log n)

    归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。作为一种典型的分而治之思想的算法应用,归并排序的实现由两种方法:
    (1)自上而下的递归(所有递归的方法都可以用迭代重写,所以就有了第 2 种方法);
    (2)自下而上的迭代;
    和选择排序一样,归并排序的性能不受输入数据的影响,但表现比选择排序好的多,因为始终都是 O(nlogn) 的时间复杂度。代价是需要额外的内存空间。
    D6C20628-3FDF-48AE-9115-BEB4C2C424961685c01b7f84849b.gif
    【基本思想】
    将一个大的无序数组有序,我们可以把大的数组分成两个,然后对这两个数组分别进行排序,之后在把这两个数组合并成一个有序的数组。由于两个小的数组都是有序的,所以在合并的时候是很快的。通过递归的方式将大的数组一直分割,直到数组的大小为 1,此时只有一个元素,那么该数组就是有序的了,之后再把两个数组大小为1的合并成一个大小为2的,再把两个大小为2的合并成4的 ….. 直到全部小的数组合并起来。

    【算法步骤】
    1、申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;
    2、设定两个指针,最初位置分别为两个已经排序序列的起始位置;
    3、比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置;
    4、重复步骤 3 直到某一指针达到序列尾;
    5、将另一序列剩下的所有元素直接复制到合并序列尾。

    1. public class MergeSort {
    2. public static void sort(int[] arr){
    3. // 在排序前,先建好一个长度等于原数组长度的临时数组,避免递归中频繁开辟空间
    4. int[] temp = new int[arr.length];
    5. mergeSort(arr, 0, arr.length-1, temp);
    6. }
    7. /**
    8. * 分+合
    9. */
    10. private static void mergeSort(int[] arr, int left, int right, int[] temp) {
    11. if (left < right) {
    12. // 拆分成两个数组
    13. int mid = (left + right) / 2;
    14. // 左边归并排序,使得左子序列有序
    15. mergeSort(arr, left, mid, temp);
    16. // 右边归并排序,使得右子序列有序
    17. mergeSort(arr, mid+1, right, temp);
    18. // 将两个有序数组合并
    19. merge(arr, left, mid, right, temp);
    20. }
    21. }
    22. /**
    23. * 合并函数,把两个有序的数组合并起来
    24. * @param arr 待排序数组
    25. * @param left 左边索引
    26. * @param mid 中间索引
    27. * @param right 右边索引
    28. * @param temp 临时中转数组
    29. */
    30. private static void merge(int[] arr, int left, int mid, int right, int[] temp) {
    31. // 左数组开始指针
    32. int i = left;
    33. // 右数组开始指针
    34. int j = mid + 1;
    35. // 临时中转数组开始指针
    36. int t = 0;
    37. // 1、依次比较左右两个数组,有序放入中转数组中
    38. while(i <= mid && j <= right) {
    39. if (arr[i] <= arr[j]) {
    40. temp[t++] = arr[i++];
    41. } else {
    42. temp[t++] = arr[j++];
    43. }
    44. }
    45. // 2、右数组为空时,将剩余左数组放入中转数组中
    46. while(i <= mid) {
    47. temp[t++] = arr[i++];
    48. }
    49. // 3、左数组为空时,将剩余右数组放入中转数组中
    50. while(j <= right) {
    51. temp[t++] = arr[j++];
    52. }
    53. // 4、将结果拷贝到原数组中
    54. t = 0;
    55. while(left <= right) {
    56. arr[left++] = temp[t++];
    57. }
    58. }
    59. public static void main(String[] args) {
    60. int[] arr = SortUtil.getArr(8);
    61. System.out.println("归并排序前:" + Arrays.toString(arr));
    62. sort(arr);
    63. System.out.println("归并排序后:" + Arrays.toString(arr));
    64. }
    65. }