算法导论 2-1思考题 合并排序中对小数组采用插入排序

在合并排序中对小数组采用插入排序。
注:书里的那个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)).

         如果仅仅由两个字表合并,则每个数据被查找且移动一次,而n/k个字表时,每个数组查找且移动lg(n/k)次,

           故为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;  
}  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值