版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wk1134314305/article/details/78216690
本文针对《Algorithms》Fourth Edition书中的归并排序做一个总结,当做学习笔记以作记录。
1,归并排序的算法原理
归并排序算法的步骤为:
(1)将数组逐步拆分成两个子数组,直至每个数组的大小为1。
(2)因为分割到最后,数组的大小为1,因此,这个时候,就相当于数组已经排序
(3)对数组进行两两合并排序,首先是合并数组大小为1的子数组,合并完之后数组大小为2,然后继续合并排序,得到大小为4的数组。这样逐层进行下去,得到了最终的大小为N的数组(即排序完毕)。
上面是对归并排序算法的一个综述。图中描述了归并排序算法的关键步骤。归并排序算法的关键步
(1)将数组分为两个子数组
(2)分别对两个子数组进行排序
(3)对两个数组进行合并,得到了最终的排序数组
对于已经排序好的两个子数组怎么进行合并,合并成一个有序的数组呢?
下面的图片很好的解释了这个过程:
上面的数组的排序过程就是利用了两个指针,i和j,分别指向左边的子数组和右边的子数组。i,j初始的时候都指向各个数组的第一个元素。如果谁指向的那个元素比较小,那就将这个元素放进新数组。如果i或者j一直移动到了自己所指向数组的最后一个元素,那么就将另一个指针指向的数组的剩余没有遍历的数组放进新数组。
下面用图例来说明这一过程:
这样就得到了一个有序的大数组。
另外,可以通过动画查看,归并排序算法的过程
归并排序动画展示
2,归并排序的两种类型
归并排序有两种算法,自顶向下和自底向上。
2.1 自顶向下归并排序
排序算法如下图所示
这种算法是从顶部开始,向下迭代分隔合并进行的。
2.2自底向上的排序算法
这种算法是从底部最小大小(最小大小为1的数组)的数组进行合并排序,逐层向上排序进行的。
3,代码
package sort;
public class MergeSort {
public static void main(String[] args) {
int[] arr={9,6,4,0};
// sort(arr, 0, arr.length-1);
sort(arr);
printarr(arr);
}
/**
* 1,自顶向下归并排序
* @param arr 要排序的数组
*/
public static void sort(int[] arr,int lo,int hi){
if(hi<=lo) return;
int mid=(lo+hi)/2;
sort(arr, lo, mid);
sort(arr, mid+1, hi);
merge(arr,lo,mid,hi);
printarr(arr);
}
/**
* 下面的方法是对已经排序好的两个子序列进行归并、排序操作,得到一个从小到大的序列
* @param arr
* @param lo
* @param mid
* @param hi
*/
public static void merge(int[] arr,int lo,int mid,int hi){
int[] arr_new=new int[arr.length];
for(int i=lo;i<=hi;i++){
arr_new[i]=arr[i];
}
int i=lo;
int j=mid+1;
for(int k=lo;k<=hi;k++){
if(i>mid) arr[k]=arr_new[j++];
else if(j>hi) arr[k]=arr_new[i++];
else if(arr_new[i]>arr_new[j]) arr[k]=arr_new[j++];
else arr[k]=arr_new[i++];
}
}
/**
* 2,自底向上归并排序
* @param arr
*/
public static void sort(int[] arr){
int N=arr.length;
for(int arr_size=1;arr_size<N;arr_size=2*arr_size){
for(int lo=0;lo<N-arr_size;lo+=arr_size*2){
merge(arr,lo,lo+arr_size-1,Math.min(lo+2*arr_size-1, N-1));
}
}
}
public static void printarr(int[] arr){
for(int i=0;i<arr.length;i++){
System.out.print(arr[i]);
System.out.print(" ");
}
System.out.println();
}
}
4,时间复杂度
时间复杂度为O(Nlog(N)),关于时间复杂度的证明,可以参考《Algorithms》Fourth Edition中的证明,这部分不在本文的范围内。同时需要注意的是:
归并排序算法的一个缺点就是:
需要一个临时数组来复制原数组的值,因此空间复杂度为O(N)。