暴力判断素数、埃氏筛法、欧拉筛法
筛法是一种用来求素数的方法。一般来说可以循序渐进的掌握暴力判断素数、埃氏筛法、欧拉筛法。
暴力判断素数
时间复杂度 O(n²/2)(对于打出素数表来说)(我太蒻了,这个时间复杂度不保证正确)
利用素数只能被1和它本身整除的性质,我们可以把数x与2到n-1全取余。如果结果均不等于0,则为素数。
代码
1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 5 using namespace std; 6 7 int n; 8 bool flag; 9 10 int main() 11 { 12 scanf("%d",&n); 13 14 for(int i=2;i<=n;i++) 15 { 16 flag=true; 17 for(int j=2;j<=i-1;j++) 18 { 19 if(i%j==0) 20 { 21 flag=false; 22 //当出现第一个能被整除的数时立即跳出循环,可提高一定效率 23 break; 24 } 25 } 26 27 if(flag) printf("%d ",i); 28 } 29 30 return 0; 31 }
这个最简单的写法在只判断几个素数时绰绰有余,但是当要打出一个很大的素数表时就很狼狈了。
埃氏筛法
时间复杂度 O(nloglogn)
很容易想到,任意一个素数的倍数是合数,这就是埃氏筛法筛出素数表的原理。假设要打出n以内的素数表。我们从2开始向后遍历,每当遇到一个素数p时,便利用此素数将[2,n]内p*2,p*3,p*4......这些合数全部筛去。
代码
1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cmath> 5 6 using namespace std; 7 8 int n; 9 int p[10000010]; 10 11 int main() 12 { 13 scanf("%d",&n); 14 15 //初始化 16 for(int i=2;i<=n;i++) p[i]=1; 17 18 for(int i=2;i<=sqrt(n)+0.5;i++) 19 for(int j=i*2;j<=n;j+=i) p[j]=0; 20 21 for(int i=2;i<=n;i++) 22 if(p[i]) printf("%d ",i); 23 24 return 0; 25 }
这个算法在一般的数据面前已经足够了。不过我们还可以更快:)
欧拉筛法
时间复杂度 O(n)
首先观察一下埃氏筛法。在使用他时,我们发现有这样一个问题:在使用素数2进行筛去操作时,我们会筛去素数6;在之后利用素数3进行筛去操作时,我们又会筛去一次素数6。可见在埃氏筛法的筛去过程中,会出现同一个合数筛去多次的情况,以至于影响了效率。
相比之下,欧拉筛法是一种线性筛法。它便解决了埃氏筛法中一个合数会被筛去多次的问题,确保了每一个合数都只会被筛去一次,因此具有O(n)的效率。而它的实现原理是确保每个合数都只会被它的最小质因数筛掉。过程大概如下:
首先我们会建立2个数组,isp(值为1/0,isp[i]用来表示i是否是素数),p(用来储存所有的素数)。依旧是打出到n的素数表。
1.将i从2开始遍历。如果i是素数,就把它加入到p[]中。
2.在当前i的情况下遍历p[],筛去i*p[j],若i*p[j]>n(已经没必要筛去了)或i%p[j]==0(这是确保每个合数只筛一次的核心)就退出循环。
对核心的解释:假设在i%p[j]==0时我们继续进行,便筛去了合数i*p[j+1]。由于此时i%p[j]==0,则这个由一个素数和一个合数的乘积组成的合数,一定能转化为一个更小的素数和一个更大的合数的乘积,那么当继续运行时,此合数必然还会被p[j]再次筛去,便进行了多余的筛去工作。因此可以说在i%p[j]==0时退出循环是确保每个合数都只会被它的最小质因数筛掉,也就是确保每个合数只被筛一次的核心。
代码
1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 5 using namespace std; 6 7 int n; 8 int num=0; 9 int isp[10000010],p[10000010]; 10 11 int main() 12 { 13 scanf("%d",&n); 14 15 //初始化 16 for(int i=2;i<=n;i++) isp[i]=1; 17 18 for(int i=2;i<=n;i++) 19 { 20 if(isp[i]) 21 { 22 num++; 23 p[num]=i; 24 } 25 for(int j=1;j<=num&&i*p[j]<=n;j++) 26 { 27 isp[i*p[j]]=0; 28 //确保每个合数都只会被它的最小质因数筛掉 29 if(i%p[j]==0) break; 30 } 31 } 32 33 for(int i=1;i<=num;i++) printf("%d ",p[i]); 34 35 return 0; 36 }

浙公网安备 33010602011771号