简单素数筛选法介绍(数论初步) By ACReaper
我们介绍一下素数筛选法。
给你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)