问题:查找 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 是给定候选数下面的素数的数量,外循环运行for( n th prime number - 2 )次。
如何以Big O表示法推导出该算法的复杂性?
提前致谢。
答案 0 :(得分:1)
素数定理表明,渐近地,小于n
的素数的数量等于n/log n
。因此,您的内部循环将运行The i * max
= n / log n * n
次(假设max
= n
)。
此外,您的外部循环运行大约n log n
次,使得n / log n * n * n log n = n^3
的总复杂度为Theta。换句话说,这不是最有效的算法。
请注意,周围有更好的近似值(例如n
- 素数更接近:
n log n + n log log n - n + n log log n / log n + ...
但是,既然你只关心大O,这种近似就足够了。
此外,还有更好的算法可用于执行您要执行的操作。查看pseudoprimes主题,了解更多信息。
答案 1 :(得分:1)
在伪代码中,您的代码是
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&#39; Neill分析此算法in her widely known JFP article并将其复杂性推导为 O(n ^ 2)。
基本上,生成的每个 n 素数都与它之前的所有素数配对(通过测试)(即 k-1 素数,对于 k th prime)和算术级数 0 ...(n-1)之和为(n-1)n / 2 这是 O(n ^ 2);并且她表明复合材料没有贡献任何比总和更重要的术语,因为在去往 n th prime的途中有O(n log n) composites但是is_empty
计算提前失败。
这是怎么回事: m = n log n ,会有 m / 2 evens,其中每一个{{1}计算只需 1 步; m / 3 3 的倍数, 2 步骤; m / 5 3 步骤;等。
复合材料的总贡献高估不处理多重性(基本上,计算 15 两次,作为 3的倍数和 5 等),是:
is_empty
不等式可以在Wolfram Alpha cloud sandbox上作为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
进行测试( 0.99921 ,对于更大的 n 进行测试,测试到 n = 2,000,000 ,其中 0.963554 )。