来源百度百科:
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
一、基本思想
将数组分为两个数组,两个数组再使用递归再拆分为若干个小数组,小数组排序完成后,合并起来,最后将两个大数组合并起来即可。
二、过程
- 递归拆分数组,当数组中只有一个元素时,停止拆分
- 合并数组时,比较两个数组中最小的值先进数组
- 判断哪个数组还不为空,将不为空的全部填入数组
三、总结
代码:
/**
* 归并排序
* @Author: Han-YLun
* @date 2019/4/22
* @Version 1.0
*/
public class MergeSort {
/**
* 将数组分为两部分,最后合并起来
* @param arr 排序的数组
* @param left 数组开始的下标
* @param right 数组结束的下标
*/
public static void mergeSortInternally(int[] arr,int left,int right){
//递归结束条件
if (left >= right)
return;
//计算left到right的中间位置,防止(left+right)超过int类型的最大值
int center = left + (right - left) / 2;
//分治递归
mergeSortInternally(arr,left,center);
mergeSortInternally(arr,center+1,right);
//将arr[left...center]和arr[center+1...right]合并为arr[left...right]
merge(arr,left,center,right);
}
/**
* 将数组arr分成两部分,并且进行排序存储后合并
* @param arr 需要排序的数组
* @param left 数组的起始位置
* @param center 数组的中间位置
* @param right 数组的结束位置
*/
private static void merge(int[] arr,int left,int center,int right){
int i = left;
int j = center+1;
int k = 0;
//申请一个和arr大小一样的临时数组
int[] tmp = new int[right-left+1];
//当两个子数组位置都没超过范围是
while (i <= center && j <= right){
if (arr[i] <= arr[j]){
tmp[k++] = arr[i++];
}else{
tmp[k++] = arr[j++];
}
}
//判断两个子数组哪个数组有剩余的数据
while(i <= center){
tmp[k++] = arr[i++];
}
while(j <= right){
tmp[k++] = arr[j++];
}
//将tmp中的数组拷回arr数组
for (int l = 0; l <= right-left; l++) {
arr[left+l] = tmp[l];
}
}
private static void main(String[] args) {
int[] arr = {1,56,2,56,3,58,6,2,5,6};
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
mergeSortInternally(arr,0,arr.length-1);
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
}
四、归并排序的优化
- 只在排序前开辟一次空间
- 归并前判断是否还有必要归并没有
- 当递归到数组足够小时,使用插入排序
四、结论
- 归并排序不是原地排序算法
- 归并排序是稳定的排序算法
- 归并排序时间复杂度为O(nlogn)
如果文章有错的地方欢迎指正,大家互相交流。