经典算法之归并排序
归并逻辑
归并是采用分治和递归的思想完成的,主要是将数组分成多个小数组,保证小数组内数字有序。
例如:
1, 0, 4, 3, 7, 10, 5, 9
分治之后会形成1,0,4,3,7,10,5,9八个只含有一个数字的数组,并保证每一个子数组有序
然后进行合并1,0, 形成0,1然后4,3,形成3,4, 依次类推 最后形成 单个有序子数组
再将数组合并 递归调用 最后形成完整有序数组
代码实现
//定义一个数组用于存储中间过程数据
int[] tmp;
public int[] sortArray(int[] nums) {
// 初始化中间数组
tmp = new int[nums.length];
mergeSort(nums, 0, nums.length - 1);
return nums;
}
private void mergeSort(int[] nums, int l, int r) {
if (l >= r) return;
int mid = (l + r) >> 1;
// 因为排序要对所有元素 索引 包含mid
mergeSort(nums, l, mid);
mergeSort(nums, mid + 1, r);
// 因为mid 为左数组临界 索引j不能包含mid
int i = l, j = mid + 1;
int cnt = 0;
// 进行分治 mid 为左数组临界 r为右数组临界 l,mid + 1 分别为左右数组开始临界
while (i <= mid && j <= r) {
if (nums[i] <= nums[j]) {
tmp[cnt++] = nums[i++];
} else {
tmp[cnt++] = nums[j++];
}
}
while (i <= mid) {
tmp[cnt++] = nums[i++];
}
while (j <= r) {
tmp[cnt++] = nums[j++];
}
for (int k = 0; k < r - l + 1; k++) {
nums[k + l] = tmp[k];
}
}
讲解:
定义 mergeSort(nums, l, r) 函数表示对 nums 数组里 [l,r] 的部分进行排序,整个函数流程如下:
1. 递归调用函数 mergeSort(nums, l, mid) 对 nums 数组里 [l,mid] 部分进行排序。
2. 递归调用函数 mergeSort(nums, mid + 1, r) 对 nums 数组里 [mid+1,r] 部分进行排序。
3. 此时 nums 数组里 [l,mid] 和 [mid+1,r] 两个区间已经有序,我们对两个有序区间线性归并即可使 nums 数组里 [l,r] 的部分有序。
4. 线性归并的过程并不难理解,由于两个区间均有序,所以我们维护两个指针 i 和 j 表示当前考虑到 [l,mid] 里的第 i 个位置和 [mid+1,r] 的第 j 个位置。
如果 nums[i] <= nums[j] ,那么我们就将 nums[i] 放入临时数组 tmp 中并让 i += 1 ,即指针往后移。否则我们就将 nums[j] 放入临时数组 tmp 中并让 j += 1 。
如果有一个指针已经移到了区间的末尾,那么就把另一个区间里的数按顺序加入 tmp 数组中即可。
这样能保证我们每次都是让两个区间中较小的数加入临时数组里,那么整个归并过程结束后 [l,r] 即为有序的。

浙公网安备 33010602011771号