我们介绍一下素数筛选法。
给你1---n的连续整数,把这些数中的素数筛选出来,用到的思路很简单。其原理基于,对于数p如果p的倍数存在与表中,则这个p的倍数一定不是素数,我们可以把它删除,但是这样删除的干净吗?这是个好问题,我们可以从小到大,从2开始枚举,至于1为什么不行,想想也应该能明白吧,然后可以用数学归纳法证明,当结束时,整张表必然是素数表,因为除了1和它本身,没有其它的数能整除。
先写出无改进版本的:
#include <stdio.h>
#define MAXN 10000000
int vis[MAXN];
int n;
int main(){
while(scanf("%d",&n) != EOF){
for(int i = 2; i <= n; i++){
for(int j = 2 * i; j <= n; j += i)
vis[j] = 1;
}
for(int i = 2; i <=n; i++ ){
if(!vis[i]){
printf("%3d ",i);
}
}
}
return 0;
}
那么这个算法的效率是多少呢?O(n * n)?当然不是了。可以这么算循环循环总的次数 小于 n/2 + n/3 + n /4 + .... + n / n 这个值,学过高等数学的数列求和的应该会把,= O(n * log n)。
下面来改进代码·,我们可以很容易观察到,上面存在重复的运算,因为对于3,9,他们也有相同的公倍数,也就是所对于选中的i,在i之前的2 --- I - 1 的倍数早就被删处了,不用在重复删除了,所以j = I * i。
int m = sqrt(n + 0.5);
int c = 0;
memset(vis,0,sizeof(vis));
for(int i = 2; i <= m; i++){
if(!vis[i]){
prime[c++] = i;
for(int j = i * i; j <=n; j+= i)
vis[j] = 1;
}
}
顺便说下素数定理:
pai(x)等价于 x / ln (x)