「这是我参与2022首次更文挑战的第14天,活动详情查看:2022首次更文挑战」。
前言
上一章节讲述了快速排序, 回顾上次快速排序他采用了双指针的思想来进行排序,而这次我们所讲述的归并排序使用了另一种方法来实现,对于以前的排序方法他们的空间利用都不会很大,但是归并是唯一一个空间占用很高的一个排序算法,其实有一点空间换时间的味道。
归并排序分析
平均时间复杂度 O(nlog下标2 n) 时间复杂度最坏 O(nlog下标2 n) 时间复杂度最好 O(nlog下标2 n) 空间复杂度为 o(n) 稳定性为稳定
通过上面参数发现归并排序的各方面时间都非常优秀,在众多排序算法中属于是佼佼者了,但是归并在弓箭复杂度上的占用比其他排序会多一点,因为在排序过程中归并需要不断地创建外部空间来实现,对于巨大的数据量归并就显得不是那么的合适了,有可能还会造成栈溢问题。
归并排序思路
经过上述分析后我们讲一下归并排序的实现思路,归并排序使用的思想主要是分治和递归,分治意思是分而治之,也就是大事化小、小事化了,来进行分开治理。递归就是一直调用自己,递归要注意一个点就是递归一定要有一个临界点。这个临界点决定了递归什么时候停止,没有临界点和无限循环一样是没有尽头的。归并则是结合两者的特点来进行的排序,它先进行一个分组,每次对半分开直到每个元素都是一组后进行归并,归并的过程就是创建一个连续空间来存储元素,在存储过程中判断两个归并的数组的大小来依次进入这个新的数组,一直递归回去就完成了归并排序。
归并排序代码实现
/**
* 归并排序
*/
@Test
public void testMergeSort(){
mergeSort(arr, 0, arr.length - 1);
System.out.println(getArr(arr));
}
public static int[] mergeSort(int[] a, int low, int high) {
int mid = (low + high) / 2;
if (low < high) {
mergeSort(a, low, mid);
mergeSort(a, mid + 1, high);
//进行归并
merge(a, low, mid, high);
}
return a;
}
public static void merge(int[] a, int low, int mid, int high) {
int[] temp = new int[high - low + 1];
int i = low;
int j = mid + 1;
int k = 0;
// 转移元素进入temp新数组,这里temp也就是归并借助的空间,也是归并的空间换时间之处
while (i <= mid && j <= high) {
if (a[i] < a[j]) {
temp[k++] = a[i++];
} else {
temp[k++] = a[j++];
}
}
while (i <= mid) {
temp[k++] = a[i++];
}
while (j <= high) {
temp[k++] = a[j++];
}
for (int x = 0; x < temp.length; x++) {
a[x + low] = temp[x];
}
}