题目
题目描述
用筛法求之N内的素数。
输入描述
N
输出描述
0~N的素数
样例输入
100
样例输出
2
3
5
7
11
13
17
19
23
29
31
37
41
43
47
53
59
61
67
71
73
79
83
89
97
题解
分析
题目要求用筛法求素数。
什么筛法呢?
- 先假定从2开始逐次递增的一组数全部为素数,
- 从小到大逐个取出(假设取出的数为x),则x除了它本身以外的全部倍数均不是素数,将x的倍数从这组数筛除。
例如:
起始的数为2~100
- 假设这组数全部为素数
- 取出第一个数2
- 2除了本身以外的倍数均不是素数,如4,6,8,10,12等。将这些数筛除。
- 以此类推,取出第二个数,重复筛除倍数的操作。
假设取出的数为x。
当x = 2时,x为素数。
当x > 2时,因为x不能被 2~x-1中的数整除,所以x也为素数。
因此取出的数x必为素数。
代码参考(基础版)
#include<stdio.h>
#define MAX 100000
#define NIL -1 //筛除标志
int a[MAX];
int main()
{
int n,i,j;
scanf("%d",&n);
for(i = 0;i <= n;i++)
a[i] = i; //初始化数组
a[0] = a[1] = NIL; //删除0和1
for(i = 2;i <= n;i++)
{
if(a[i] != NIL)
{
for(j = a[i] * 2;a[j] <= n;j += i)
a[j] = NIL;
}
}
for(i = 0;i <= n;i++)
if(a[i] != NIL)
printf("%d\n",a[i]);
return 0;
}
代码分析
该代码利用了筛法的最基本思路实现。适合初学者参考。
但在速度和空间利用率上,可以被进一步优化,请看进阶版代码。
代码参考(进阶版)
#include<cstdio>
#include<vector>
using namespace std;
int main()
{
int n;
vector<bool> a;
scanf("%d",&n);
a.resize(n + 1); //初始化时默认值为false。我们设值false表示未被筛除,true表示被筛除。下标为对应的数
a[1] = a[0] = true; //将0和1筛除
for(int i = 0;i <= n;i++)
{
if(!a[i])
{
printf("%d\n",i);
for(int j = i + i;j <= n;j += i)
a[j] = true;
}
}
return 0;
}
代码分析
- 借助C++的vector类进行实现,存储空间可以根据数据规模而改变,大大提升了数据的空间利用率。
- 并且不再将数本身直接存储在数组中,而是用bool类型的标志变量。相比于使用int的变量,进一步较小的空间的消耗。
- 计算速度方面,由于vector默认初始变量值为false,所以无需再使用for循环进行初始化。相比于基础版,免去了一个线性时间消耗。
- 因为for循环每次取出的未被筛除的数都是素数,所以可以把结果输出与筛法算法执行过程结合,再次减小了一个线性时间消耗。
题解为本人原创。
如有疏漏欢迎指正。
欢迎在评论区和我共同探讨、学习交流呀。
原创不易,转载请说明出处。