前面介绍过如何判断一个正整数是否是素数,如果我们要筛选出[1,n]范围内的所有素数,前面介绍的方法是使用循环枚举每一个整数i并在循环体中使用循环来判断i是否为素数:
#include<iostream>
using namespace std;
int main()
{
int n;
cin>>n;
for(int i=2;i<=n;i++){
int find = 0;
for(int j=2;j*j<=i;j++){
if(i%j==0){
find = 1;
break;
}
}
if(find==0) cout<<i<<" ";
}
return 0;
}
#include<iostream>
using namespace std;
int main()
{
int n;
cin>>n;
for(int i=2;i<=n;i++){
int find = 0;
for(int j=2;j*j<=i;j++){
if(i%j==0){
find = 1;
break;
}
}
if(find==0) cout<<i<<" ";
}
return 0;
}
#include<iostream> using namespace std; int main() { int n; cin>>n; for(int i=2;i<=n;i++){ int find = 0; for(int j=2;j*j<=i;j++){ if(i%j==0){ find = 1; break; } } if(find==0) cout<<i<<" "; } return 0; }
其实还有一种效率更高的方法——筛选法。具体步骤如下:
首先将[1,n](这里以[1,100]为例)的所有整数书写出来:

首先划去2的倍数(不包括2):

然后划去3的倍数(同样不包括3):

接下来,因为4已经被划去了,不用考虑,然后划去5的倍数(不包括5):

接一下依次考虑后面的数,只要没被划掉,那就把这个数的倍数划去(不包括自身)。最后一个考虑的数是\sqrt{100},也就是10(不用考察到最后一个数100)。全部处理后结果如下:

可以使用数组来记录整数是否被划掉,根据上述步骤可以得出参考程序:
#include<iostream>
using namespace std;
const int N = 10000;
int a[N+1]; //全局数组元素a[i]记录整数i是否被划掉,默认值为0,正好表示没有被划掉
int main()
{
int n;
cin>>n;
a[1] = 1; //1不是素数,划掉
for(int i=2;i*i<=n;i++){ //从2开始考察,一直到sqrt(n)
//考察整数i
if(a[i]==0){ //数字i没有被划掉
//把i的2倍,3倍,4倍,…,的数都划掉
for(int j=i+i;j<=N;j+=i){
a[j]=1;
}
}
}
for(int i=1;i<=n;i++){
if(a[i]==0) cout<<i<<" "; //如果i没有被划掉,输出i
}
return 0;
}
#include<iostream>
using namespace std;
const int N = 10000;
int a[N+1]; //全局数组元素a[i]记录整数i是否被划掉,默认值为0,正好表示没有被划掉
int main()
{
int n;
cin>>n;
a[1] = 1; //1不是素数,划掉
for(int i=2;i*i<=n;i++){ //从2开始考察,一直到sqrt(n)
//考察整数i
if(a[i]==0){ //数字i没有被划掉
//把i的2倍,3倍,4倍,…,的数都划掉
for(int j=i+i;j<=N;j+=i){
a[j]=1;
}
}
}
for(int i=1;i<=n;i++){
if(a[i]==0) cout<<i<<" "; //如果i没有被划掉,输出i
}
return 0;
}
#include<iostream> using namespace std; const int N = 10000; int a[N+1]; //全局数组元素a[i]记录整数i是否被划掉,默认值为0,正好表示没有被划掉 int main() { int n; cin>>n; a[1] = 1; //1不是素数,划掉 for(int i=2;i*i<=n;i++){ //从2开始考察,一直到sqrt(n) //考察整数i if(a[i]==0){ //数字i没有被划掉 //把i的2倍,3倍,4倍,…,的数都划掉 for(int j=i+i;j<=N;j+=i){ a[j]=1; } } } for(int i=1;i<=n;i++){ if(a[i]==0) cout<<i<<" "; //如果i没有被划掉,输出i } return 0; }
其实还可以通过线性筛(欧拉筛)算法来提高程序执行效率,线性筛算法的思路是:从2到n的每一个整数(无论质数合数)i,筛掉 小于i的最小质因子的所有质数 的i倍的数(由此可见数学理论对算法设计的重要性)。
例如筛选过程中考察到整数77,77分解质因数是7 \times 11,最小质因子是7,那么需要筛掉所有小于7的质数(2、3、5)的77倍的那些整数,也就是筛掉2 \times 77、3 \times 77、5 \times 77。
#include<iostream>
using namespace std;
const int N = 10000;
int a[N+1]; //全局数组元素a[i]记录整数i是否被筛去
int b[N+1]; //全局数组b记录所有素数
int main()
{
//cnt计数器,记录找到素数的个数
int n,cnt = 0;
cin>>n;
for(int i=2;i<=n;i++){
if(a[i]==0) b[cnt++] = i; //i没有被筛掉,是素数,记录到数组b中
//将记录素数的数组b每个元素的i倍筛掉
for(int j=0;j<cnt && i*b[j]<=n;j++){
a[b[j]*i] = 1; //筛掉b[j]的i倍
if(i%b[j]==0) break; //只考虑数组b中小于i的最小质因子的那些素数
}
}
for(int i=0;i<cnt;i++){
cout<<b[i]<<" ";
}
return 0;
}
#include<iostream>
using namespace std;
const int N = 10000;
int a[N+1]; //全局数组元素a[i]记录整数i是否被筛去
int b[N+1]; //全局数组b记录所有素数
int main()
{
//cnt计数器,记录找到素数的个数
int n,cnt = 0;
cin>>n;
for(int i=2;i<=n;i++){
if(a[i]==0) b[cnt++] = i; //i没有被筛掉,是素数,记录到数组b中
//将记录素数的数组b每个元素的i倍筛掉
for(int j=0;j<cnt && i*b[j]<=n;j++){
a[b[j]*i] = 1; //筛掉b[j]的i倍
if(i%b[j]==0) break; //只考虑数组b中小于i的最小质因子的那些素数
}
}
for(int i=0;i<cnt;i++){
cout<<b[i]<<" ";
}
return 0;
}
#include<iostream> using namespace std; const int N = 10000; int a[N+1]; //全局数组元素a[i]记录整数i是否被筛去 int b[N+1]; //全局数组b记录所有素数 int main() { //cnt计数器,记录找到素数的个数 int n,cnt = 0; cin>>n; for(int i=2;i<=n;i++){ if(a[i]==0) b[cnt++] = i; //i没有被筛掉,是素数,记录到数组b中 //将记录素数的数组b每个元素的i倍筛掉 for(int j=0;j<cnt && i*b[j]<=n;j++){ a[b[j]*i] = 1; //筛掉b[j]的i倍 if(i%b[j]==0) break; //只考虑数组b中小于i的最小质因子的那些素数 } } for(int i=0;i<cnt;i++){ cout<<b[i]<<" "; } return 0; }