【问题标题】:Time complexity finding n primes with trial division by all preceding primes时间复杂度找到 n 个素数,并用所有前面的素数进行试除
【发布时间】:2017-11-24 20:48:51
【问题描述】:

问题:找到 n 个素数。

#include<stdio.h>
#include<stdlib.h>

void firstnprimes(int *a, int n){

    if (n < 1){
        printf("INVALID");
        return;
    }

    int i = 0, j, k;                // i is the primes counter

    for (j = 2; i != n; j++){       // j is a candidate number

        for (k = 0; k < i; k++)
        {
            if (j % a[k] == 0)      // a[k] is k-th prime
                break;
        }

        if (k == i)                 // end-of-loop was reached
            a[i++] = j;             // record the i-th prime, j
    }
    return;
}

int main(){
    int n;
    scanf_s("%d",&n);
    int *a = (int *)malloc(n*sizeof(int));
    firstnprimes(a,n);
    for (int i = 0; i < n; i++)
        printf("%d\n",a[i]);
    system("pause");
    return 0;
}

我的函数的内部循环运行 i 次(最多),其中 i 是低于给定候选数的素数的数量,外部循环运行第 (n 个素数 - 2) 次。

如何以大 O 表示法推导出该算法的复杂性?

提前致谢。

【问题讨论】:

  • 旁白:您不需要检查 all 以前的素数作为因子 - 只需检查那些 a[k] * a[k] <= j; 而且偶数也不需要检查。
  • ... 除了2 这是唯一的偶数。所以用2初始化数组后,外循环可以是for (j = 3; i != n; j+=2)

标签: c time-complexity big-o primes


【解决方案1】:

素数定理指出,渐近地,小于n的素数等于n/log n。因此,您的内部循环将运行 i * max =n / log n * n 次的 Theta(假设 max=n)。

此外,您的外循环按n log n 次的顺序运行,使n / log n * n * n log n = n^3 的总复杂度Theta。换句话说,这不是最有效的算法。

请注意,周围有更好的近似值(例如,n-th 素数更接近:

n log n + n log log n - n + n log log n / log n + ...

但是,由于您只关心大 O,因此这个近似值就足够了。

此外,还有更好的算法来做你想做的事情。查找伪素数主题,了解更多信息。

【讨论】:

  • 我的意思是我的内循环最多运行 i 次。
【解决方案2】:

在伪代码中,您的代码是

firstnprimes(n) = a[:n]   # array a's first n entries
    where
       i = 0
       a = [j for j in [2..]  
                if is_empty( [j for p in a[:i] if (j%p == 0)] )
                   && (++i) ]

(假设短路的is_empty 在发现列表非空后立即返回false)。

它所做的是测试从 2 开始的每个候选数,并通过其所有前面的素数。

Melissa O'Neill 分析此算法in her widely knownJFParticle 并得出其复杂度为O(n^2)

基本上,产生的每个 n 个素数都与它之前的所有素数(即 k-1 个素数,对于k th prime)和等差数列0...(n-1)的和是(n-1)n/2这是 O( n^2 );她表明,复合词对总和的贡献没有任何比它更重要的项,因为有 O(n log n) composites 在通往 n th 素数的路上,但 is_empty 计算 对他们来说提前失败了


事情是这样的:m = n log n,会有 m/2 个偶数,is_empty 的计算只需要 1 步; m/3 3 的倍数,2 步; m/53 个步骤;等等。

所以复合的总贡献,高估不处理多重性(基本上,计数 15 两次,作为两者的倍数 3 em> 和 5 等),是:

SUM{i = 1, ..., n} (i m / p_i)          // p_i is the i-th prime
= m SUM{i = 1, ..., n} (i / p_i)
= n log(n) SUM{i = 1, ..., n} (i / p_i)
< n log(n) (n / log(n))                 // for n > 14,000 
= n^2

不等式可以在Wolfram Alpha cloud sandbox 处测试为Sum[ i/Prime[i], {i, 14000}] Log[14000.0] / 14000.00.99921,随着 n 的增大而减小,测试到 n = 2,000,000 它是 0.963554)。

【讨论】:

  • 谢谢。我们可以简化这个寻找 n 个素数的代码吗?
  • 用什么语言? C? ——简化,还是优化以提高速度?后者需要更复杂的代码(添加一两个新测试)。或者算法可能会完全改变,特别是从您的试用部门到sieve-of-eratosthenes。在 SO 上的primes 中有很多关于此的问答。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-22
  • 1970-01-01
  • 2020-11-03
  • 1970-01-01
  • 1970-01-01
  • 2013-10-29
相关资源
最近更新 更多