Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 合并排序究竟进行了多少次比较?_Algorithm_Sorting_Complexity Theory_Quicksort_Mergesort - Fatal编程技术网

Algorithm 合并排序究竟进行了多少次比较?

Algorithm 合并排序究竟进行了多少次比较?,algorithm,sorting,complexity-theory,quicksort,mergesort,Algorithm,Sorting,Complexity Theory,Quicksort,Mergesort,我已经读到,在实践中,快速排序比合并排序快得多,其原因是隐藏常量 随机快速排序复杂性的解决方案是2nlnn=1.39nlogn,这意味着快速排序中的常数是1.39 但是合并排序呢?合并排序中的常量是什么?合并两个大小分别为kresp的排序数组(或列表)m最多进行k+m-1比较,最多进行min{k,m}。(每次比较后,我们可以向目标写入一个值,当两个值中的一个用完时,就不需要再进行比较了。) 设C(n)为n元素数组(列表)的合并排序的最坏比较数 很明显,我们有C(1)=0,C(2)=1。此外,我们

我已经读到,在实践中,快速排序比合并排序快得多,其原因是隐藏常量

随机快速排序复杂性的解决方案是2nlnn=1.39nlogn,这意味着快速排序中的常数是1.39

但是合并排序呢?合并排序中的常量是什么?

合并两个大小分别为
k
resp的排序数组(或列表)
m
最多进行
k+m-1
比较,最多进行
min{k,m}
。(每次比较后,我们可以向目标写入一个值,当两个值中的一个用完时,就不需要再进行比较了。)

C(n)
n
元素数组(列表)的合并排序的最坏比较数

很明显,我们有
C(1)=0
C(2)=1
。此外,我们还有复发

C(n) = C(floor(n/2)) + C(ceiling(n/2)) + (n-1)
一个简单的归纳说明

C(n) <= n*log_2 n

C(n)让我们看看能否解决这个问题

在合并排序中,我们在递归的每个级别执行以下操作:

  • 将阵列一分为二
  • 对每一半进行递归排序
  • 使用合并算法将两半合并在一起
  • 那么,每一步要做多少比较呢?好吧,分割步骤不会进行任何比较;它只是将阵列一分为二。步骤2没有(直接)进行任何比较;所有比较都是通过递归调用完成的。在步骤3中,我们有两个大小为n/2的数组,需要合并它们。这最多需要n个比较,因为合并算法的每个步骤都会进行一次比较,然后消耗一些数组元素,所以我们只能进行n个比较

     #include<iostream>
     using namespace std;
     int  count=0; /* to count the number of comparisions */
    
     int merge( int arr [ ], int l, int m, int r)
    {
     int i=l; /* left subarray*/
     int j=m+1; /* right  subarray*/
     int k=l; /* temporary array*/
     int temp[r+1];
     while( i<=m && j<=r)
     {
       if ( arr[i]<= arr[j])
      {
        temp[k]=arr[i];
        i++;
      }
       else
      {
        temp[k]=arr[j];
        j++;
      }
        k++;
        count++;
    
      }
       while( i<=m)
      {
        temp[k]=arr[i];
        i++;
        k++;
      }
        while( j<=r)
      {
        temp[k]=arr[j];
        j++;
        k++;
      }
      for( int p=l; p<=r; p++)
      {
        arr[p]=temp[p];
      }
       return count;
      }
    
    
      int  mergesort( int arr[ ], int l, int r)
      {
        int comparisons;
        if(l<r)
      {
       int m= ( l+r)/2;
       mergesort(arr,l,m);
       mergesort(arr,m+1,r);
       comparisions = merge(arr,l,m,r);
      }
       return comparisons;
      }
    
     int main ()
     {
       int size;
       cout<<" Enter the size of an array "<< endl;
       cin>>size;
       int myarr[size];
       cout<<"  Enter the elements of array "<<endl;
       for ( int i=0; i< size; i++)
     {
       cin>>myarr[i];
     }
     cout<<"  Elements of array before sorting are  "<<endl;
     for ( int i=0; i< size; i++)
     {
       cout<<myarr[i]<<"  " ;
     }
      cout<<endl;
      int c=mergesort(myarr, 0, size-1);
      cout<<"  Elements of array after sorting are  "<<endl;
      for ( int i=0; i< size; i++)
     {
       cout<<myarr[i]<<"  " ;
     }
       cout<<endl;
       cout<<"  Number of comaprisions while sorting the given array"<< c <<endl;
       return 0;
     }
    
    结合这一点,我们得到以下结果:

    C(1) = 0
    C(n) = 2C(n / 2) + n
    
    (如评论中所述,线性项更精确地表示为(n-1),尽管这不会改变总体结论。我们将使用上述递归作为上限。)

    为了简化这个过程,让我们定义n=2k并用k重写这个循环:

    C'(0) = 0
    C'(k) = 2C'(k - 1) + 2^k
    
    这里的前几个术语是0,2,8,24。这看起来像k2k,我们可以用归纳法证明。作为我们的基本情况,当k=0时,第一项为0,k2k的值也为0。对于归纳步骤,假设索赔适用于一些k,并考虑K+ 1。那么这个值是2(k2k)+2k+1=k2k+1+2k+1=(k+1)2k+1,所以这个声明对k+1有效,完成归纳。因此,C’(k)的值是k2k。因为n=2k,这意味着,假设n是2的完美幂,我们得到的比较次数是

    C(n)=n lg n

    令人印象深刻的是,这比快速排序更好!那么,为什么快速排序比合并排序快呢?这与其他因素有关,而这些因素与所做比较的数量无关。基本上,由于快速排序在适当的位置工作,而合并排序在适当的位置工作,所以在合并排序中引用的位置不如在快速排序中好。这是一个巨大的因素,在实践中,快速排序比合并排序要好得多,因为缓存丢失的成本非常巨大。此外,排序数组所需的时间不仅仅考虑比较的数量。其他因素(如每个数组元素移动的次数)也很重要。例如,在合并排序中,我们需要为缓冲元素分配空间,移动元素以便可以合并它们,然后合并回数组。在我们的分析中,这些动作并不算在内,但它们肯定是合二为一的。将此与quicksort的分区步骤进行比较,quicksort的分区步骤只移动每个数组元素一次,并保持在原始数组中。这些额外的因素,而不是所做比较的数量,支配着算法的运行时间

    该分析比最佳分析的精度稍低,但证实了该分析大致为n lg n,并且与quicksort的平均情况相比,这确实是较少的比较

    希望这有帮助

    合并排序为O(n logn),在每个步骤中,在“最坏”情况下(对于比较次数),执行比较


    另一方面,快速排序在最坏的情况下是O(n^2)。

    在最坏的情况下,假设采用直接实现,则对n个元素进行排序的比较次数为

    N⌈lg n⌉ − 2.⌈lg n⌉ + 1. 其中lg n表示n的值


    这个结果可以在Donald Knuth的或最新版本的中找到,我刚刚写下了一个证明。

    C++程序来计算合并排序中的比较数。 首先,程序将对给定数组进行排序,然后显示比较次数

     #include<iostream>
     using namespace std;
     int  count=0; /* to count the number of comparisions */
    
     int merge( int arr [ ], int l, int m, int r)
    {
     int i=l; /* left subarray*/
     int j=m+1; /* right  subarray*/
     int k=l; /* temporary array*/
     int temp[r+1];
     while( i<=m && j<=r)
     {
       if ( arr[i]<= arr[j])
      {
        temp[k]=arr[i];
        i++;
      }
       else
      {
        temp[k]=arr[j];
        j++;
      }
        k++;
        count++;
    
      }
       while( i<=m)
      {
        temp[k]=arr[i];
        i++;
        k++;
      }
        while( j<=r)
      {
        temp[k]=arr[j];
        j++;
        k++;
      }
      for( int p=l; p<=r; p++)
      {
        arr[p]=temp[p];
      }
       return count;
      }
    
    
      int  mergesort( int arr[ ], int l, int r)
      {
        int comparisons;
        if(l<r)
      {
       int m= ( l+r)/2;
       mergesort(arr,l,m);
       mergesort(arr,m+1,r);
       comparisions = merge(arr,l,m,r);
      }
       return comparisons;
      }
    
     int main ()
     {
       int size;
       cout<<" Enter the size of an array "<< endl;
       cin>>size;
       int myarr[size];
       cout<<"  Enter the elements of array "<<endl;
       for ( int i=0; i< size; i++)
     {
       cin>>myarr[i];
     }
     cout<<"  Elements of array before sorting are  "<<endl;
     for ( int i=0; i< size; i++)
     {
       cout<<myarr[i]<<"  " ;
     }
      cout<<endl;
      int c=mergesort(myarr, 0, size-1);
      cout<<"  Elements of array after sorting are  "<<endl;
      for ( int i=0; i< size; i++)
     {
       cout<<myarr[i]<<"  " ;
     }
       cout<<endl;
       cout<<"  Number of comaprisions while sorting the given array"<< c <<endl;
       return 0;
     }
    
    #包括
    使用名称空间std;
    整数计数=0;/*计算比较的次数*/
    整数合并(整数arr[],整数l,整数m,整数r)
    {
    int i=l;/*左子阵列*/
    int j=m+1;/*右子阵列*/
    int k=l;/*临时数组*/
    内部温度[r+1];
    
    然而,如果没有更多的细节,这个问题没有答案。答案取决于(1)你对复杂性的定义:操作次数?比较次数?(2)不同机器的答案可能不同,这取决于每台机器的指令集。当然是比较的次数。这意味着我的1.39快速排序常量不正确。@geniaz1-你的快速排序常量确实正确,但由于其他原因,快速排序更快。有关详细信息,请参阅我的帖子。非常感谢!我有什么分析可以将空间分配计算在内吗?公式不应该是C(1)=0 C(n)=2C(n/2)+n-1。因为如果我们有两个大小为n/2的数组,我们最多需要n-1个比较来将它们合并到一个大小为n的数组中吗?@Johnson是的!这是一个很好的观点。这将使整体分析减少2n-1(每个递归调用一个),我相信这不会改变结论。谢谢你这么做!合并中的比较次数不应该是(n-1)吗?有没有快速排序的想法?