归并排序的思想还是很简单的,但我之前也有的烦恼:一看就会,一写就废。看着不就是简单的分和并嘛,为啥一写就一脸懵逼。
所以我决定来捋一捋归并排序,捋完发现写代码比思想还简单嘛。
1.首先要记住归并排序的一些重点: 核心思想是分而治之,需要用到O(N)的额外空间 。根据这两点可以确定归并方法的参数
//nums是原数组,left和right是左右边界下标,因为要分而治之
//temp是额外的辅助数组
mergeSort(int[] nums, int left, int right, int[] temp)
2.把参数写上之后,思路会明确很多,归并排序的步骤就是
-
排序好左边
-
排序好右边
-
然后左右合并即可
-
看递归终止条件条件,如果说left == right的话,一个数是自然有序的,所以if里判断是left<right。
public void mergeSort(int[] nums, int left, int right, int[] temp) {
if (left < right) {
int mid = (left + right) / 2;
mergeSort(nums, left, mid, temp);
mergeSort(nums, mid+1, right, temp);
merge(nums, left, mid, right, temp);//合并
}
}
3.再来看merge方法,合并的操作,现在问题变成了类似:
两个有序数组合并成一个有序数组, 辅助数组的意义就是在此
-
先将两个数组的数字依次比较大小,有序的放入辅助数组
-
再将辅助数组拷贝给原数组。
public void merge(int[] nums, int left, int mid, int right, int[] temp) {
//为什么需要额外变量?
//因为left和right后面还要用做数组拷贝
int l = left, r = mid + 1, index = left;
while (l <= mid && r <= right) {
if (nums[l] > nums[r]) {
temp[index++] = nums[r++];
k += mid - l + 1;
} else {
temp[index++] = nums[l++];
}
}
while (l <= mid) {
temp[index++] = nums[l++];
}
while (r <= right) {
temp[index++] = nums[r++];
}
//合并完成,然后进行拷贝工作
for (int i = left; i <= right; i++) {
nums[i] = temp[i];
}
}
感兴趣的兄弟们可以看看这道题,就是用到归并排序的思想 。数组中的逆序对