法一:暴力法
简而言之,就是根据素数的定义去筛选,即只能被1和本身整除。这种做法的弊端也显而易见——太耗时。本地测试了一下,最多筛选到十万左右。
代码如下:
#include<iostream>
#include<cmath>
using namespace std;
int prime[10010];
int main()
{
prime[0]=2;prime[1]=3;
int k=2;
for(int i=4;i<=100000;i++)
{
bool flag=true;
for(int j=2;j<=sqrt(i);j++)
{
if(i%j==0)
{
flag=false;
break;
}
}
if(flag)
{
prime[k++]=i;
}
}
for(int i=0;i<k;i++)cout<<prime[i]<<' ';
return 0;
}
法二:埃拉托色尼(Eratosthenes)筛法
思想:对于不超过n的每个非负整数p,删除2p,3p,4p…..,当处理完所有数后,还没有被处理的数就是素数。筛个几十万不成问题。
代码如下:
#include<iostream>
#include<cmath>
using namespace std;
int prime[3000010];
int main()
{
int n;
cin>>n;
prime[1]=1;
for(int i=2;i<=sqrt(n+0.5);i++)
{
if(!prime[i])
{
for(int j=i*i;j<=n;j+=i)prime[j]=1;
}
}
for(int j=1;j<=n;j++)
if(!prime[j])cout<<j<<' ';
return 0;
}
法三:筛选法
思路:类似于埃式筛选法,只不过它是先将偶数标记,然后对于奇数,筛去以它为因子的其他数。
代码如下:
#include<iostream>
#include<cmath>
using namespace std;
int prime[3000010];
int main()
{
int n;
cin>>n;
prime[1]=1;
for(int i=4;i<=n;i+=2)prime[i]=1;
for(int j=3;j<=sqrt(n+0.5);j+=2)
{
for(int k=j+j;k<=n;k+=j)prime[k]=1;
}
for(int i=1;i<=n;i++)
{
if(!prime[i])cout<<i<<' ';
}
return 0;
}
但这样存在重复筛选,所以有了法四
法四:线性筛(欧拉法)
思想:首先,先明确一个条件,任何合数都能表示成一系列素数的积。
然后利用了每个合数必有一个最小素因子,每个合数仅被它的最小素因子筛去正好一次。所以为线性时间。
代码中体现在:
if(i%prime[j]==0)break;
prime数组 中的素数是递增的,当 i 能整除 prime[j],那么 i*prime[j+1] 这个合数肯定被 prime[j] 乘以某个数筛掉。
因为i中含有prime[j], prime[j] 比 prime[j+1] 小。接下去的素数同理。所以不用筛下去了。
在满足i%prme[j]==0这个条件之前以及第一次满足改条件时,prime[j]必定是prime[j]*i的最小因子。
代码如下:
#include<iostream>
#include<cstring>
using namespace std;
const int MAXN=3000001;
int prime[MAXN];//保存素数
bool vis[MAXN];//初始化
int main()
{
int cnt=0,n;
cin>>n;
memset(vis,0,sizeof(vis));
for(int i=2;i<n;i++)
{
if(!vis[i])
prime[cnt++]=i;
for(int j=0;j<cnt&&i*prime[j]<n;j++)
{
vis[i*prime[j]]=1;
if(i%prime[j]==0)//保证了每个合数只被他最小的素数因子筛去
break;
}
}
for(int i=0;i<cnt;i++)
cout<<prime[i]<<' ';
return 0;
}