归并排序就是先把左半边数组排好序,再把右半边数组排好序,然后把两半数组合并。

    1. // 定义:排序 nums[lo..hi]
    2. void sort(int[] nums, int lo, int hi) {
    3. if (lo == hi) {
    4. return;
    5. }
    6. int mid = (lo + hi) / 2;
    7. // 利用定义,排序 nums[lo..mid]
    8. sort(nums, lo, mid);
    9. // 利用定义,排序 nums[mid+1..hi]
    10. sort(nums, mid + 1, hi);
    11. /****** 后序位置 ******/
    12. // 此时两部分子数组已经被排好序
    13. // 合并两个有序数组,使 nums[lo..hi] 有序
    14. merge(nums, lo, mid, hi);
    15. /*********************/
    16. }
    17. // 将有序数组 nums[lo..mid] 和有序数组 nums[mid+1..hi]
    18. // 合并为有序数组 nums[lo..hi]
    19. void merge(int[] nums, int lo, int mid, int hi);
    1. class Merge {
    2. // 用于辅助合并有序数组
    3. private static int[] temp;
    4. public static void sort(int[] nums) {
    5. // 先给辅助数组开辟内存空间
    6. temp = new int[nums.length];
    7. // 排序整个数组(原地修改)
    8. sort(nums, 0, nums.length - 1);
    9. }
    10. // 定义:将子数组 nums[lo..hi] 进行排序
    11. private static void sort(int[] nums, int lo, int hi) {
    12. if (lo == hi) {
    13. // 单个元素不用排序
    14. return;
    15. }
    16. // 这样写是为了防止溢出,效果等同于 (hi + lo) / 2
    17. int mid = lo + (hi - lo) / 2;
    18. // 先对左半部分数组 nums[lo..mid] 排序
    19. sort(nums, lo, mid);
    20. // 再对右半部分数组 nums[mid+1..hi] 排序
    21. sort(nums, mid + 1, hi);
    22. // 将两部分有序数组合并成一个有序数组
    23. merge(nums, lo, mid, hi);
    24. }
    25. // 将 nums[lo..mid] 和 nums[mid+1..hi] 这两个有序数组合并成一个有序数组
    26. private static void merge(int[] nums, int lo, int mid, int hi) {
    27. // 先把 nums[lo..hi] 复制到辅助数组中
    28. // 以便合并后的结果能够直接存入 nums
    29. for (int i = lo; i <= hi; i++) {
    30. temp[i] = nums[i];
    31. }
    32. // 数组双指针技巧,合并两个有序数组
    33. int i = lo, j = mid + 1;
    34. for (int p = lo; p <= hi; p++) {
    35. if (i == mid + 1) {
    36. // 左半边数组已全部被合并
    37. nums[p] = temp[j++];
    38. } else if (j == hi + 1) {
    39. // 右半边数组已全部被合并
    40. nums[p] = temp[i++];
    41. } else if (temp[i] > temp[j]) {
    42. nums[p] = temp[j++];
    43. } else {
    44. nums[p] = temp[i++];
    45. }
    46. }
    47. }
    48. }