1.算法思想:
①将待排序的序列一分为二
②对左右子序列排序
③子序列合并,使原序列有序
主要函数代码:
public static void mergeSort(int[ ] a, int left, int right)
{
if (left<right)
{//至少有2个元素
int i=(left+right)/2; //计算中分点
mergeSort(a, left, i); //在第一个子集合上分类(递归)
mergeSort(a, i+1, right); //在第二个子集合上分类(递归)
merge(a, b, left, i, right); //合并到数组b
copy(a, b, left, right); //复制回数组a
}
}
2.代码实现:
①归并分类算法存在的问题 :
- 递归层次太深
在mergeSort的执行过程中,当集合仅含有两个元素时,仍要进一步做递归调用,直至每个集合仅含有一个元素时才退出递归调用。集合含有相当少的元素时,较深层次的递归调用使得时间过多地消耗在处理递归上。
- 元素在数组 a 和辅助数组 b 之间的频繁移动
每次归并,都要首先将A中的元素移到 b 中,再由 b 复制到 a 的对应位置上。
②消去递归后:
- 先将每两个相邻的大小为 1 的子序列归并
对上一次归并得到的大小为 2 的子序列进行相邻归并
……
最后归并到一个序列,归并过程完成。
- 通过轮流地将元素从 a 归并到b,并从b 归并到a,可以消除复制过程。
void mergeSort(int* a,int n){ int b [n]; int s=1; while(s<n){ mergePass(a, b, n, s); //合并到数组b s+=s; mergePass(b, a, n, s); //合并到数组a s+=s; } }
功能函数:
void mergePass(int* x, int*y,int n, int s) { //合并大小为s的相邻子数组
int i = 0;
while(i<n-2*s){//合并大小为s的相邻2段子数组
merge(x, y, i, i+s-1, i+2*s-1);
i=i+2*s;
}
//剩下的元素少于2s
if(i+s<n)
merge(x, y, i, i+s-1, n-1);
else//复制到y
for(int j=i; j<n; j++)
y[j]=x[j];
}
void merge(int* c, int* d, int l, int m, int r) { //合并c[l : m ] 和 c[m+1 : r] 到d[l : r]
int i =l, j=m+1, k=l;
while ( (i<=m) && (j<=r) )
if ( c[ i ] <= c[ j ] )
d[k++] = c[i++];
else d[k++] = c[j++];
if(i>m)
for(int q=j;q<=r;q++)
d[k++] = c[q];
else
for(int q=i;q<=m;q++)
d[k++] = c[q];
}
3.复杂度分析:
m=2 k=2 d=1,
4.数据测试
规模n | 10 | 100 | 1000 | 10000 | 100 000 | 200 000 |
耗时/s | 2e-006 | 9.8e-006 | 8.49e-005 | 1.2261e-003 | 1.33002e-2 | 2.56657e-2 |