提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
归并排序
一般用在数据量很大的外部排序(放到磁盘上的,内存放不下)
分治思想:分而治之
归并排序:先划分成(/2,向下取整,把mid也划分到左边)直到都只有单独的一个元素,再合并的过程就是排序的过程。
合并排序,哪一个更小就放在前面,怎么拆分的就怎么合并回去,比较要合并的数组的最前面的元素大小就行,因为他俩是排好序的(升序),选出去的较小就不用管了,接着比较两个数组中剩余的元素的各自第一个元素的大小。
将两个有序表合并成一个称为二路归并
下面那些合并排序的数组都要存到临时数组中,再放回到原来的数组中。
比如9、5排成5、9了,原来划分的95来源于952那么就合并回去,那95这个子数组的第一个元素和2这个数组的第一个元素比较,谁小就放前面;把第一次合并的数组(此时仍然是被划分的)再合并
划分时怎么知道划分成为一个一个的呢
分治:采用递归,最后left和right相遇了即相等时就意味着只剩一个了。
首先要有个mid,分而治之左边和右边
merge 合并并且排序,谁小把谁拉下来
1、比较两个归并数组的第一个元素,第一个数组的开始位置是s1=left,第二个数组的是s2=mid+1,而临时数组temp的长度就是int[r-l+1] 3-0+1;
2、如比较大小后,拉下来一个元素,temp的下标就i++,同时s2++,同理i++,s1++;加入s2++后大于了right,那就要退出循环了,此时还应该判断左边还有没有元素即判断s1还是不是小于mid,小于那就还有,直接拷贝剩下元素进temp数组;同理万一右边数组还有元素呢,同理操作。
复杂度与稳定性:
时间复杂度:由于是均匀分割的和快排用的基准数那种没关系,所以归并排序最好最坏都是O(nlogn)
空间复杂度:O(n)
归并排序是稳定的排序,稳定性:其实这个概念就是说,如果待排序的序列中存在值相等的元素,经过排序之后,相等元素之间原有的先后顺序不变。
注意:
任何一个稳定的排序都可以实现为不稳定的排序,但是如果它本身就是一个不稳定的排序,那么它就不可能实现为一个稳定排序。
为什么添加一个等号就是稳定的排序?
常用排序算法复杂度对比:
代码实现:
搞懂原理,一步一步写就行。
public static void mergeSort(int[] arr, int left, int right) {
if (left >= right){ // 递归出口,当left和right相等时跳出
return;
}
int mid = (right + left) >>> 1; // 无符号右移一位 / 2
mergeSort(arr, left, mid);
mergeSort(arr, mid + 1, right);
merge(arr, left, mid, right); // 合并
}
private static void merge(int[] arr, int left, int mid, int right) {
int l1 = left;
int r1 = mid + 1;
int[] temp = new int[right - left + 1];
int i = 0; // i表示temp数组的下标
while (l1 <= mid && r1 <= right) {
if (arr[l1] <= arr[r1]){
temp[i++] = arr[l1++];
}else {
temp[i++] = arr[r1++];
}
}
while (l1 <= mid){
temp[i++] = arr[l1++];
}
while (r1 <= right){
temp[i++] = arr[r1++];
}
for (int j = 0; j < temp.length; j++){
arr[j + left] = temp[j];
}
}
参考了很多老师们的讲解,感谢知识共享的年代~