归并排序算法的原理如下:对于给定的一组记录(假设有n个记录),首先将每两个相邻的长度为1的序列进行归并,得到n/2(向上取整数)个长度为2或1的有序子序列,再将其两两合并,反复执行此过程,直到得到一个有序序列。
所以,归并排序的关键就是前两步:
第一步:划分半子表;
第二步:合并半子表。
以数组{49,38,65,97,76,13,27}为例,归并排序的具体步骤如下:
初始关键字:[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]
程序代码如下:
package chapter8;
public class MergeSortTest {
public static void mergeSort(int[] data){
sort(data,0,data.length-1);
}
public static void sort(int[] data,int left,int right){
if(left>=right)
return;
//找出中间索引
int center=(left+right)/2;
//对左边数组进行递归
sort(data,left,center);
//对右边数组进行递归
sort(data,center+1,right);
//合并
merge(data,left,center,right);
print(data);
}
/**
* 将两个数组进行归并,归并前面2个数字已有序,归并后依然有序
* @param data 数组对象
* @param left 左数组的第一个元素的作引
* @param center 左数组的最后一个元素的作引,center+1是右数组第一个元素的索引
* @param right 右数组最后一个元素的索引
*/
public static void merge(int[] data,int left,int center,int right){
//临时数组
int[] tmpArr=new int[data.length];
//右数组第一个元素索引
int mid=center+1;
//third记录临时数组的索引
int third=left;
//缓存左数组第一个元素的索引
int tmp=left;
while(left<=center && mid<=right){
//从两个数组中取出最小的放入临时数组
if(data[left]<=data[mid]){
tmpArr[third++]=data[left++];
}else{
tmpArr[third++]=data[mid++];
}
}
//剩余部分一次放入临时数组(实际上两个while只会执行其中一个)
while(mid<=right){
tmpArr[third++]=data[mid++];
}
while(left<=center){
tmpArr[third++]=data[left++];
}
//将临时数组中的内容拷贝回原数组中
//(原left-right范围的内容被复制回原数组)
while(tmp<=right){
data[tmp]=tmpArr[tmp++];
}
}
public static void print(int[] data){
for(int i=0;i
程序运行结果:
5 3 6 2 1 9 4 8 7
3 5 6 2 1 9 4 8 7
3 5 6 2 1 9 4 8 7
3 5 6 1 2 9 4 8 7
1 2 3 5 6 9 4 8 7
1 2 3 5 6 4 9 8 7
1 2 3 5 6 4 9 7 8
1 2 3 5 6 4 7 8 9
1 2 3 4 5 6 7 8 9
排序后的数组:
1 2 3 4 5 6 7 8 9
归并排序算法复杂度分析: 最好时间:O(nlogn)
平均时间:O(nlogn)
最坏时间:O(nlogn)
辅助存储:O(n)
稳定性:稳定
备注:n大时较好