Eratosthenes筛选法(埃拉托斯特尼筛法)
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int vist[1000000];
int n,m;
void suan()
{
int i,j;
for(i=2;i*i<=1000005;i++){//筛选1到 1000005的素数 ,注意第一个循环是i*i<=m
if(!vist[i]){
for(j=i*i;j<=1000005;j=j+i){//让j为i的倍数 ,j<=m
if(!vist[j]){
vist[j]=1;
}
}
}
}
}
int main()
{
int c,i,j;
memset(vist,0,sizeof(vist));
vist[0]=vist[1]=1;//注意0和1直接标记为1,证明不是素数
suan();//先预处理1到1000005的素数作为标记;
while(1){
scanf("%d%d",&n,&m);
int cnt=0;
if(n==-1&&m==-1){
break;
}
for(i=n;i<=m;i++){//统计计算n到 m的范围素数的个数
if(vist[i]==0) cnt++;//vist[i]==0证明没有被标记,即为素数;
}
printf("%d\n",cnt);
}
}
**
欧拉筛选法
**
1 任何一个合数都可以表示成一个质数和一个数的乘积
2即一个合数(x)与一个质数(y)的乘积可以表示成一个更大的合数(z)与一个更小的质数(a)的乘积
这也是理解代码中 if(i%primes[j] == 0)break;的关键
```cpp
#include<iostream>
#include<cstring>
using namespace std;
const int M=10000000;
int vist[M];
int prime[M];
int Prime(int n)
{
int i,j,cnt=0;
memset(vist,0,sizeof(vist));
for(i=2;i<=n;i++){
if(!vist[i]){//没有被标记过,证明是素数
prime[++cnt]=i;//素数的个数 ++cnt;(注意是先++,因为第一个素数是 2);
}
for(j=1;j<=cnt&&i*prime[j]<=n;j++){//从小的prime开始枚举(所以j=1开始) ,不能超过已经知道的prime,所以就j<=cnt
// 并且i*这个prime不能超出统计范围n ,减少循环的次数
vist[i*prime[j]]=1; // 素数的倍数肯定是合数,所以筛去
if(i%prime[j]==0) break; //如i=9,vist[i*prime[j]],prime的值从2,3,直到9%3==0即(i%prime[j]==0)跳出
//因为下一个有prime[3]=5,9*5=45,而45可以等到i=15,prime[2]=3的时候,避免重复计算
}
}
return cnt;
}
int main()
{
int n;
cin>>n;//要计算多少就输n为多少
memset(prime, 0, sizeof(prime));
int count=Prime(n);
for(int i=1;i<=n;i++){
if(prime[i]){
cout<<prime[i]<<endl;
}
}
printf("\n1-n的素数个数有%d个\n",count);
}
***总结两种筛选法的i都是从2开始的。***