1.归并排序简介
_ 归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,
该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,
再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
归并排序是一种稳定的排序方法。_
简而言之:
== 1. 把数组拆分
2. 然后把数组合并,在合并的过程中排序==
归并排序运用的分治的思想,优势体现在此,把一个长的数组(长度为n)排序拆分为若干个小数组排序,小数两两组合并后,数组总数变成了n / 2 , 把合并后的数组内部排序,再合并,再排序…直到合并成为长度为n的数组。
拆分过程
合并排序过程
到了这里长数组已经被拆分为n个长度为 1 的 小数组。
如何实现合并排序
归并排序中相对重要的就是合并排序的时候所用的方法,即两个有序数组的排序。我们就拿上图合并到的最后数组举例。
先设置两个数组的开始点,左边third 右边rightStart。在创建一个和原数组一样大大小的数组tmpArray[],我们要把比较后小的数存放到这个数组中。
两个数组都是有序的,比较third 和 rightStart 位置上的数,2 < 3, rightStart 自加1 ,把2存入 tmpArray , 再次比较third 和 rightStart 位置上的数,3 < 10,third 自加1,把3存入tmpArray…
当third大于middle,或者rightStar大于right时停止比较。
比较停止后有两种情况
1.third到头了,但是rightStar没到头(抵达middle)。因为两个数组都是有序的,我们只需要把rightStar后面的数全部移动到 tmpArray 后面即可。
2.rightStar到头了,但是third没到头,我们把third后面(middle之前)的数直接移动tmpArray 后面即可。
2.代码实现
public class MergeSort {
/**
* 核心方法
*/
public void mergeSort(int [] a,int left,int right) {
if (left < right) {
int middle = (left + right)/2;
mergeSort(a, left, middle);
//这里有个小错误哦
mergeSort(a, middle + 1, right);
merge(a,left,middle,right);
}
}
/**
* 合并数组
*/
public void merge(int []a,int left,int middle,int right) {
//需要一个新的数组在存
int [] tmpArray = new int [a.length];
int rightStart = middle+1;
int third = left;
int tmp = left;
//还用if啊 用while
while(left <= middle && rightStart <= right) {
if (a[left] <= a[rightStart]) {
tmpArray[third ++] = a[left++];
}else {
tmpArray[third ++] = a[rightStart++];
}
}
while(left<=middle){
tmpArray[third++] = a[left++];
}
//如果右边还有数据......
while(rightStart<=right){
tmpArray[third++] = a[rightStart++];
}
while(tmp<=right){
a[tmp] = tmpArray[tmp++];
}
}
3.法优缺点
优点:
一, 归并排序的效率达到了巅峰:时间复杂度为O(nlogn),这是基于比较的排序算法所能达到的最高境界
二, 归并排序是一种稳定的算法(即在排序过程中大小相同的元素能够保持排序前的顺序,3212升序排序结果是1223,排序前后两个2的顺序不变),这一点在某些场景下至关重要
三, 归并排序是最常用的外部排序方法(当待排序的记录放在外存上,内存装不下全部数据时,归并排序仍然适用,当然归并排序同样适用于内部排序…)
缺点:
归并排序需要O(n)的辅助空间,而与之效率相同的快排和堆排分别需要O(logn)和O(1)的辅助空间,在同类算法中归并排序的空间复杂度略高