归并排序利用的是递归和分治技术实现的,将待排序列划分成越来越小的子序列,即,递归划分成长度为1的子序列,并进行归并,得到n/2(上取整)个长度为2或者1的子序列,然后再将这些子序列两两归并,直到得到一个完整的子序列为止。
对于待排序列[49,38,65,97,76,13,27],先划分再合并
待排序列:[49 38 65 97 76 13 27]
长度为1子序列:[49] [38] [65] [97 ] [76] [13] [27]
一趟归并: [38 49] [65 97] [13 76] [27]
二趟归并: [38 49 65 97] [13 27 76]
三趟归并: [13 27 38 49 65 76 97]
在归并过程中,子序列的排序实现:
根据子序列划分的中间值n/2,也就是代码中的q,p为子序列的起始索引,r为子序列的末尾索引,这样就将一个(p,r)的子序列划分成(p,q)和(q+1,r)的两个序列,设为a,b,定义两个数组分别存放a,b两个序列,分别用一个小标i,j标注a,b两个序列,如果a[i] < b[j],就把小的值a[i]存放在另一个数组中,相反,则把b[j]存放在另一个数组中;若最终b的序列遍历完,而a中还有元素没有遍历,则需要把a中的剩余元素存放在另一个数组中,反之,则存放b中元素。注:另个一个数组是长度为两数组之和的新的数组,把p作为起始位置存放。
具体的代码实现如下
MergeSort.java
public class MergeSort {
public static void main(String[] args){
int[] a = {49,38,65,97,76,13,27};
mergeSort(a,0,a.length-1);
for (int i = 0; i < a.length; i ++){
System.out.print( a[i] + "\t" );
}
}
private static void mergeSort(int[] a, int p, int r) {
if (p<r){
int q = (p+r)/2;
mergeSort( a,p,q);
mergeSort( a,q+1,r);
merge(a,p,q,r);
}
}
private static void merge(int[] a, int p, int q, int r) {
int n1 = q-p+1;
int n2 = r-q;
int[] b = new int[n1];
int[] c = new int[n2];
int i , j , k;
for (i = 0, k = p; i < n1; i ++, k++){
b[i] = a[k];
}
for (i = 0; i < n2 ; i ++, k ++){
c[i] = a[k];
}
for (i = 0 , j = 0, k =p; i < n1 && j < n2; k++){
if (b[i] < c[j]){
a[k] = b[i];
i ++;
}
else {
a[k] = c[j];
j++;
}
}
if (i < n1){
for (int m = i; m < n1; m++){
a[k++] = b[m];
}
}
if (j < n2){
for (int m = j; m < n2; m++){
a[k++] = c[m];
}
}
}
}
输出:
13 27 38 49 65 76 97
算法时间复杂度分析
归并排序算法的最好、最坏、平均时间复杂度为O(nlogn),算法的辅助存储空间复杂度O(n),具有稳定性,待排序列长度大时,比较好。