在合并排序中对小数组采用插入排序。
注:书里的那个O里还有一杠的符号打不出来,所以这里用大O代替了,特指同阶无穷大量。
尽管合并排序最坏情况运行时间为O(nlgn),插入排序的最坏运行时间为O(n^2),但是插入排序的常数因子使得它在n较小时,运行要更快一些。因此,在合并排序算法中,当子问题足够小时,采用插入排序就比较合适了。考虑对合并排序做这样的修改,即采用插入排序策略,对n/k 个长度为 k 的子列表进行排序。然后,再用标准的合并机制将它们合并起来,此处k是一个待定的值。
a) 证明在最坏的情况下,n/k个子列表可以用插入排序在O(nk)的时间内完成排序
b) 证明这些子列表可以在O(nlg(n/k))最坏情况内完成合并。
c) 如果已知修改后的合并排序算法的最坏运行时间为O(nk+nlg(n/k)),要使得修改后的算法具有与标准合并算法一样的渐进运行时间,k的最大渐进值( 即O形式)是什么(以n的函数形式表示)?
注:书里的那个O里还有一杠的符号打不出来,所以这里用大O代替了,特指同阶无穷大量。
尽管合并排序最坏情况运行时间为O(nlgn),插入排序的最坏运行时间为O(n^2),但是插入排序的常数因子使得它在n较小时,运行要更快一些。因此,在合并排序算法中,当子问题足够小时,采用插入排序就比较合适了。考虑对合并排序做这样的修改,即采用插入排序策略,对n/k 个长度为 k 的子列表进行排序。然后,再用标准的合并机制将它们合并起来,此处k是一个待定的值。
a) 证明在最坏的情况下,n/k个子列表可以用插入排序在O(nk)的时间内完成排序
b) 证明这些子列表可以在O(nlg(n/k))最坏情况内完成合并。
c) 如果已知修改后的合并排序算法的最坏运行时间为O(nk+nlg(n/k)),要使得修改后的算法具有与标准合并算法一样的渐进运行时间,k的最大渐进值( 即O形式)是什么(以n的函数形式表示)?
d) 实践中,应该如何选取k值。
参考答案:
a、O(n/k*k^2)=O(nk).这里的O中间有一横
b、n/k个列表两两合并,合并完继续合并,共lg(n/k)对,合并的代价O(n).所以O(nlg(n/k)).
c、O(nk+nlg(n/k))=O(nlgn).只能最大是k=O(lgn).等式左边中第一项是高阶项。k如果大于lgn,则比归并排序复杂度大了。左边可以写成nk+nlgn-nlgk,k等于lgn时,就是2nlgn-nlglgn.忽略恒定系数,则与归并排序是一样的。
b、 实践中,k的值应该选为使得插入排序比合并排序快的最大的数组长度。很容易理解,假设k=1,那么退化为标准合并排序,那么要提高效率需放大k,k放大到使得array[k]使用插入排序比合并排序快,而array[k+1]的插入排序效率不如或等于合并排序。
#include <stdio.h>
#include <string.h>
#include <time.h>
#define BUFFER_SIZE 10
int InsertionSort(int *a,int p,int q)
{
int i=0;
int j=0;
int b[q-p+1];
memset(b,0,sizeof(b));
b[0]=a[p];
for(i=p+1;i<=q;i++)
{
j=i-p-1;
while(j>=0&&b[j]>=a[i])
{
b[j+1]=b[j];
j--;
}
b[j+1]=a[i];
}
for(i=p,j=0;i<=q;i++)
{
a[i]=b[j];
j++;
}
}
void Merge(int *a,int p,int q,int r)
{
int n1=q-p+1;
int n2=r-q;
int i=0;
int j=0;
int k=0;
int b[n1+1];
int c[n2+1];
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
b[n1]=BUFFER_SIZE;//设置哨兵元素,注意不要溢出
c[n2]=BUFFER_SIZE;//设置哨兵元素,注意不要溢出
for(i=0;i<n1;i++)
{
b[i]=a[p+i];
}
for(i=0;i<n2;i++)
{
c[i]=a[q+1+i];
}
for(i=p,j=0,k=0;i<=r;i++)
{
if(b[j]<=c[k])
{
a[i]=b[j];
j++;
}
else
{
a[i]=c[k];
k++;
}
}
}
void MergeAndInsertionSort(int *a,int p,int r,int k)
{
int q=0;
if(p>=r)
{
return;
}
q=(p+r)/2;
if((q-p+1)<=k)//子数组长度≤k的时候就不再进行划分,而是对该子数组进行插入排序
{
InsertionSort(a,p,q);
}
else
{
MergeAndInsertionSort(a,p,q,k);
}
if(r-q<=k)
{
InsertionSort(a,q+1,r);
}
else
{
MergeAndInsertionSort(a,q+1,r,k);
}
Merge(a,p,q,r);
}
void Output(int *a,int len)
{
int i=0;
for(i=0;i<len;i++)
{
printf("%d ",a[i]);
}
printf("\n");
}
int main()
{
int i=0;
int k=1;
int a[BUFFER_SIZE];
memset(a,0,sizeof(a));
srand((unsigned)time(NULL));
for(i=0;i<BUFFER_SIZE;i++)
{
a[i]=rand()%BUFFER_SIZE;
}
printf("随机生成的数组:");
Output(a,BUFFER_SIZE);
k=rand()%BUFFER_SIZE+1;
printf("k=%d\n",k);
MergeAndInsertionSort(a,0,BUFFER_SIZE-1,k);
printf("排序后的数组:");
Output(a,BUFFER_SIZE);
system("pause");
return 0;
}