思想:
将两个的有序数列合并成一个有序数列,我们称之为"归并"。归并排序:如果要将一个数组排序,可以先(递归地)将它们分成两半进行排序,然后将结果归并起来。
下面介绍另外两种方法,分别是自顶向下归并和自底向上归并,图示参考连接:https://www.cnblogs.com/chengxiao/p/6194356.html
但是我感觉里面的那个自下而上的算法感觉有点复杂,所以我总结了算法第四版上的代码,如下:
// 该方法是用于将排序后的数组归并到一起
// 主要思路就是,将数组归并到一个临时数组,然后再拷贝回原数组
public void merge(int arr[], int start, int mid, int end) {
int[] temp = new int[end - start + 1];
int i = start;// 第一个有序区的索引
int j = mid + 1;// 第二个有序区的索引
int k = 0;// 临时数组的索引
// 这是当两边的数组都没有遍历完
while (i <= mid && j <= end) {
if (arr[i] <= arr[j]) {
temp[k++] = arr[i++];
} else {
temp[k++] = arr[j++];
}
}
// 当左边的数组没有遍历完
while (i <= mid) {
temp[k++] = arr[i++];
}
// 当右边的数组没有遍历完
while (j <= end) {
temp[k++] = arr[j++];
}
// 将排序后的数组全部整合到数组arr中
for (i = 0; i < k; i++) {
arr[start + i] = temp[i];
}
}
// 自顶向下的排序方法
public void sortUpToDown(int[] arr, int start, int end) {
if (start >= end) {
return;
}
int mid = start + (end - start) / 2;// 这个好像是为了防止溢出
sortUpToDown(arr, start, mid);
sortUpToDown(arr, mid + 1, end);
merge(arr, start, mid, end);
}
// 从下到上
public void sort(int[] arr, int start, int end) {
int N = arr.length;
for (int sz = 1; sz < N; sz = sz + sz) {// sz为子数组大小
for (int lo = 0; lo < N - sz; lo += sz + sz) {
// lo为子数组索引,所以lo的取值范围的判定条件为:N-sz,因为索引的最大值为数组的长度减去子数组的长度,从数组的最右边开始算起。
merge(arr, lo, lo + sz - 1, Math.min(lo + sz + sz - 1, N - 1));
}
}
}
归并排序的时间复杂度是O(N*lgN),这里附上时间复杂度计算的参考连接:添加链接描述
空间复杂度为: O(n)