您的位置:首页 > 编程语言 > Go语言

【Data Structure/Algorithm】排序之归并排序

2017-10-12 16:42 483 查看

本文针对《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)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  归并排序 算法