归并排序有两个主要的核心步骤——拆分、合并。运用的分治的思想,在分解的过程中并没有执行具体的步骤,算法的排序实现是在合并的过程中产生的
上面的过程中我们并不难看懂分解合并的过程,在代码实现中两个比较难以理解的地方是:
1.我们知道这是一个以空间换时间的算法,其中会用到一个临时的数组,在我们mergerUtils()的方法中,有一个将临时数组中的元素赋值给元素组的过程?而且是原来的位置,可是为什么要这样呢?
我们待合并的数组是存在于我们原数组的存储位置上的,由于我们的排序思路是左右两面同时开工,所以很难设计成内部排序(个人感觉通过类似于指针的方式实现,但是如果这是通过数组来实现的话元素的移动消耗好像有点大,通过链表来实现的话应该是可以的),所以就需要一个外部的存储空间,排序完毕后我们又将元素写入原来的数组是为了方便在进行下一级的合并排序。我们将所有待排序的合并操作都放在一个数组中便于我们设计递归的实现,这样递归的实现就可以通过元素下标的变化来实现。
2.如何理解先先拆分再合并?数据的排序又是通过怎样的机制来实现的?
我们先通过递归切实左右递归来将元素彻底拆分,当拆分的不能再拆分的时候就是我们要回溯的时候了,我们的排序也正是在这时候执行的。
合并代码分析
归并排序的代码实现:
public static void mergerSort(int[] arr, int left, int right, int[] temp) {
if (left < right) {
int mid = (left + right) / 2;
mergerSort(arr, left, mid, temp);
mergerSort(arr, mid + 1, right, temp);
mergerUtils(arr, left, mid, right, temp);
}
}
public static void mergerUtils(int[] arr, int left, int mid, int right, int[] temp) {
int i = left;
int j = mid + 1;
int t = 0;
//比较左右两边的数组大小,并依次进行合并的过程
while (i <= mid && j <= right) {
temp[t++] = arr[i] <= arr[j]?arr[i++]:arr[j++];
}
//那边的数据还有剩余,我们就将剩下的元素拷贝过去
while (i <= mid) {
temp[t] = arr[i];
t += 1;
i += 1;
}
while (j <= right) {
temp[t] = arr[j];
t += 1;
j += 1;
}
//将临时数组中与已经排列好的数据复制到原数组中
t = 0;
int tempLeft = left;
while (tempLeft <= right) {
arr[tempLeft] = temp[t];
t += 1;
tempLeft += 1;
}
}