基本思想:
设归并排序的当前区间是R[low..high],分治法的三个步骤是:
①分解:将当前区间一分为二,即求分裂点
②求解:递归地对两个子区间R[low..mid]和R[mid+1..high]进行归并排序;
③组合:将已排序的两个子区间R[low..mid]和R[mid+1..high]归并为一个有序的区间R[low..high]。
递归的终结条件:子区间长度为1(一个记录自然有序)。
将两个有序序列合并成一个新的有序序列。(归并排序将数组分成一个一个元素,一个元素默认有序,从一个元素的数组开始合并起,往后的多个元素的数组是建立在前面的基础上(已经具备有序性)再进行归并的)
①把 n 个记录看成 n 个长度为 1的有序子表;
②进行两两归并使记录关键字有序,得到 n/2 个长度为 2 的有序子表;
③重复第②步直到所有记录归并成一个长度为 n 的有序表为止
重点:
1.分治的实现
2.合并的实现
分治,就是把整个集合的元素一直除2化分,一直化为到一个数组没有两个元素开始合并。
对于归并排序,其关键就在于“合并”,即如何将两个有序序列合并成一个新的有序序列。
合并的思路:新建一个数组用来存储合并总的数据,逐个判断两个数组中元素的大小,将小的放入到新数组中,并将索引加1
java代码实现:
package fanzhenhua.sort;
import java.util.Arrays;
public class MergeSort {
public static void mergeSort(DataWrap[] data){
sort(data,0,data.length-1);
}
private static void sort(DataWrap[] data,int left,int right){
//将数组一直分割下去,直到分割后的数组元素个数为1为止,也就是left>=right时就停止分割
if(left<right){
//计算分割的中点,该点默认为左边数组最后一个元素
int center=(left+right)/2;
//左分割
sort(data,left,center);
//右分割
sort(data,center+1,right);
//合并分割后的左右数组为一个数组
merge(data,left,center,right);
System.out.println(Arrays.toString(data));
}
}
//将两个有序数组进行合并
private static void merge(DataWrap[] data,int left,int center,int right){
//构建一个新的数组用来存放排序过程中的数据
DataWrap[] newData=new DataWrap[data.length];
//获取右边数组的第一个数据索引
int mid=center+1;
//定义两个中间变量,index1表示左边数组的第一个位置,index2表示newData数组的起始位置。
int index1=left;
int index2=left;
//分别对左边数组和右边数组中的数据进行比较判断,并添加进新数组中。(这种方法要求待归并的两个数组必须有序)
//归并排序利用递归的思想,将数组划分成一个元素一个元素的数组(一个元素的数组默认有序),先从一个元素的数组排序起
//往后的数组在之前排好序的基础上在进行归并
while(left<=center&&mid<=right){
//如果左边的小于右边的,则将左边数组的数据添加入新的数组中
if(data[left].compareTo(data[mid])<=0){
newData[index1++]=data[left++];
}else{//否则的话将右边数组的数据添加入新的数组中
newData[index1++]=data[mid++];
}
}
while(left<=center){
newData[index1++]=data[left++];
}
while(mid<=right){
newData[index1++]=data[mid++];
}
while(index2<=right){
data[index2]=newData[index2++];
}
}
public static void main(String[] args) {
DataWrap[] data = {
new DataWrap(25, "")
,new DataWrap(-16, "")
,new DataWrap(15, "")
,new DataWrap(23, "")
,new DataWrap(-30, "")
,new DataWrap(-49, "")
,new DataWrap(21, "*")
,new DataWrap(30, "")
,new DataWrap(3, "")
,new DataWrap(67, "")
,new DataWrap(35, "")
,new DataWrap(5, "")
,new DataWrap(7, "")
,new DataWrap(21, "")
,new DataWrap(49, "")
};
System.out.println("排序之前:" + Arrays.toString(data));
mergeSort(data);
System.out.println("排序之后:" + Arrays.toString(data));
}
}
排序过程以及结果:
算法分析:
1、稳定性
归并排序是一种稳定的排序。
2、存储结构要求
可用顺序存储结构。也易于在链表上实现。
3、时间复杂度
对长度为n的文件,需进行 lgn趟二路归并,每趟归并的时间为O(n),故其时间复杂度无论是在最好情况下还是在最坏情况下均是O(nlgn)。
4、空间复杂度
需要一个辅助向量来暂存两有序子文件归并的结果,故其辅助空间复杂度为O(n),显然它不是就地排序。
参考文章:
https://blog.youkuaiyun.com/bruce_6/article/details/39121643