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

来源:互联网 发布:手机直播源码 编辑:程序博客网 时间:2024/05/29 15:50
在合并排序中对小数组采用插入排序。
注:书里的那个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;  }  


0 0
原创粉丝点击