归并排序就是先把左半边数组排好序,再把右半边数组排好序,然后把两半数组合并。
// 定义:排序 nums[lo..hi]void sort(int[] nums, int lo, int hi) {if (lo == hi) {return;}int mid = (lo + hi) / 2;// 利用定义,排序 nums[lo..mid]sort(nums, lo, mid);// 利用定义,排序 nums[mid+1..hi]sort(nums, mid + 1, hi);/****** 后序位置 ******/// 此时两部分子数组已经被排好序// 合并两个有序数组,使 nums[lo..hi] 有序merge(nums, lo, mid, hi);/*********************/}// 将有序数组 nums[lo..mid] 和有序数组 nums[mid+1..hi]// 合并为有序数组 nums[lo..hi]void merge(int[] nums, int lo, int mid, int hi);
class Merge {// 用于辅助合并有序数组private static int[] temp;public static void sort(int[] nums) {// 先给辅助数组开辟内存空间temp = new int[nums.length];// 排序整个数组(原地修改)sort(nums, 0, nums.length - 1);}// 定义:将子数组 nums[lo..hi] 进行排序private static void sort(int[] nums, int lo, int hi) {if (lo == hi) {// 单个元素不用排序return;}// 这样写是为了防止溢出,效果等同于 (hi + lo) / 2int mid = lo + (hi - lo) / 2;// 先对左半部分数组 nums[lo..mid] 排序sort(nums, lo, mid);// 再对右半部分数组 nums[mid+1..hi] 排序sort(nums, mid + 1, hi);// 将两部分有序数组合并成一个有序数组merge(nums, lo, mid, hi);}// 将 nums[lo..mid] 和 nums[mid+1..hi] 这两个有序数组合并成一个有序数组private static void merge(int[] nums, int lo, int mid, int hi) {// 先把 nums[lo..hi] 复制到辅助数组中// 以便合并后的结果能够直接存入 numsfor (int i = lo; i <= hi; i++) {temp[i] = nums[i];}// 数组双指针技巧,合并两个有序数组int i = lo, j = mid + 1;for (int p = lo; p <= hi; p++) {if (i == mid + 1) {// 左半边数组已全部被合并nums[p] = temp[j++];} else if (j == hi + 1) {// 右半边数组已全部被合并nums[p] = temp[i++];} else if (temp[i] > temp[j]) {nums[p] = temp[j++];} else {nums[p] = temp[i++];}}}}
