【问题标题】:Time complexity of the program程序的时间复杂度
【发布时间】:2009-08-30 06:39:05
【问题描述】:
 #include<stdio.h>
 #include<time.h>

 int main()

  {

    clock_t start;
    double d;
    long int n,i,j;
    scanf("%ld",&n);
    n=100000;
    j=2;
    start=clock();
    printf("\n%ld",j);

       for(j=3;j<=n;j+=2)
       {
          for(i=3;i*i<=j;i+=2)

          if(j%i==0)
            break;

           if(i*i>j)
          printf("\n%ld",j);

        }
    d=(clock()-start)/(double)CLOCKS_PER_SEC;
    printf("\n%f",d);

}

当 n=100000 时,上述程序的运行时间为 0.015 秒。 我还在 C 中实现了埃拉托色尼筛算法,得到了 n=100000 的 0.046 的运行时间。

我上面的算法比我已经实现的 Sieve 算法快多少。

我上面的程序的时间复杂度是多少??

我的筛子的实现

 #define LISTSIZE 100000    //Number of integers to sieve<br>
 #include <stdio.h>
 #include <math.h>
 #include <time.h>

int main()
{   


    clock_t start;
    double d;
    long int list[LISTSIZE],i,j;
    int listMax = (int)sqrt(LISTSIZE), primeEstimate = (int)(LISTSIZE/log(LISTSIZE));

    for(int i=0; i < LISTSIZE; i++)
        list[i] = i+2;
    start=clock();

    for(i=0; i < listMax; i++)
    {
        //If the entry has been set to 0 ('removed'), skip it
        if(list[i] > 0)
        {
            //Remove all multiples of this prime
            //Starting from the next entry in the list
            //And going up in steps of size i
            for(j = i+1; j < LISTSIZE; j++)
            {
                if((list[j] % list[i]) == 0)
                    list[j] = 0;
            }
        }
    }
    d=(clock()-start)/(double)CLOCKS_PER_SEC;

    //Output the primes
    int primesFound = 0;
    for(int i=0; i < LISTSIZE; i++)
    {
        if(list[i] > 0)
        {
            primesFound++;

            printf("%ld\n", list[i]);
        }
    }
    printf("\n%f",d);
    return 0;
}

【问题讨论】:

  • 第二个for循环没有大括号是故意的吗?您如何格式化您的代码,以便我们知道它应该做什么。
  • 是的,第二个 for 循环没有大括号,因为它包含一个语句。上面的时间复杂度是O(n^1.5)吗?

标签: c optimization sieve-of-eratosthenes


【解决方案1】:

有许多因素可能会影响您的结果。可以肯定的是,我们需要查看您的筛子实现的代码。另外,您电脑上clock 功能的分辨率是多少?如果实施不允许毫秒级别的高精度,那么您的结果可能在您的测量误差范围内。

我怀疑问题出在这里:

            //Remove all multiples of this prime
            //Starting from the next entry in the list
            //And going up in steps of size i
            for(j = i+1; j < LISTSIZE; j++)
            {
                    if((list[j] % list[i]) == 0)
                            list[j] = 0;
            }

这是删除所有素数倍数的糟糕方法。为什么不使用内置的乘法运算符来删除倍数?这个版本应该更快:

            //Remove all multiples of this prime
            //Starting from the next entry in the list
            //And going up in steps of size i
            for(j = list[i]; j < LISTSIZE; j+=list[i])
            {
              list[j] = 0;
            }

【讨论】:

    【解决方案2】:

    我上面的程序的时间复杂度是多少??

    要凭经验测量程序的时间复杂度,您需要多个数据点。为多个 N 值运行程序,然后制作 N 与时间的关系图。您可以使用电子表格、GNUplot 或方格纸和铅笔来完成此操作。您还可以使用软件和/或简单的旧数学来找到适合您数据的多项式曲线。

    非经验性:关于分析计算复杂性的文章很多(并在计算机科学课程中讲授过)。 computational complexity theory 上的维基百科文章可能会为进一步阅读提供一些起点。

    【讨论】:

      【解决方案3】:

      您的筛子实现不正确;这就是它如此缓慢的原因:

      • 不应将其设为数字​​数组,而应设为标志数组(您仍可使用 int 作为数据类型,但 char 也可以)
      • 您不应该对数组使用索引移位,但 list[i] 应该确定 i 是否为素数(而不是 i+2 是否为素数)
      • 您应该从 i=2 开始消除
      • 通过这些修改,您应该遵循 1800 INFORMATION 的建议,并取消所有 i 的倍数,并使用以 i 为步长的循环,而不是 1 的步长

      【讨论】:

        【解决方案4】:

        只是为了您的时间复杂度:

        你有一个 ~LISTMAX 迭代的外循环和一个最大的内循环。 LISTSIZE 迭代。这意味着您的复杂性是

        O(sqrt(n)*n)

        其中 n = 列表大小。它实际上有点低,因为内部循环每次都会减少它的计数,并且只针对每个未知数运行。但这很难计算。由于 O-Notation 提供了一个上限,因此 O(sqrt(n)*n) 应该没问题。

        【讨论】:

        【解决方案5】:

        这种行为很难预测,但您应该考虑到访问内存并不便宜......对于小素数再次计算它可能会更快。

        【讨论】:

          【解决方案6】:

          这些运行时间太小而没有意义。系统时钟分辨率不准确到那种水平。

          要获得准确的时序信息,您应该做的是循环运行您的算法。重复几千次以使运行时间至少达到一秒,然后您可以将时间除以循环数。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2017-11-15
            • 2018-02-21
            • 1970-01-01
            • 1970-01-01
            • 2020-09-15
            • 2023-02-26
            • 2019-07-10
            相关资源
            最近更新 更多