前置文章:素数判断入门201808
- 关于素数的入门部分,已经在上面有写过
- 本文是讨论从 “ 埃氏筛 ” 到 “ 线性筛 ” 的那一丁点区别。
概要分析
- 埃氏筛选的原理和时间复杂度分析:
- 埃氏筛选已经很好了!但是有缺陷
- 再往前走一步:线性筛选
关于埃氏筛选法
- 百度百科用一句话就描述清楚了:
- 埃拉托斯特尼筛法,简称埃氏筛或爱氏筛,是一种由希腊数学家埃拉托斯特尼所提出的一种简单检定素数的算法。要得到自然数n以内的全部素数,必须把不大于根号n的所有素数的倍数剔除,剩下的就是素数。
- 本质是用剔除的思维,进行递推,时间复杂度的分析是:
- 第一层循环 i,需要选择从 2 到 √n 的因子;
- 第二层循环 j,表示 i*j 都是非素数;
- 所以对前 n 个数字实行 埃氏筛 的运算量应该是:
1.
2. 由式子1:
3. 接下来的证明交给数学大神 - 根据以上的推导,得到时间复杂度是
- 这是一个什么概念,用一组数据:
埃氏筛选已经很好了!但是有缺陷
- 一个合数,会被多个因子进行筛选:
- 例如 12:
- 当 i 是 2 的时候,会筛到 2 4 6 8 10 12;
- 当 i 是 3 的时候,会筛到 3 6 9 12;
- 当 i 是 4 的时候,会筛到 4 8 12;
- 当 i 是 6 的时候,会筛到 6 12;
- 这么明显的缺陷,显然要想办法解决的。
关于欧拉筛法:线性
- 居然百度百科,没有欧拉筛选,也没有线性筛选的词条。。
有兴趣的同学可以去申请去写一个咯- 欧拉筛选也叫线性筛选,是在埃筛的基础上,解决了重复筛选的合数的问题,真的只是一小步,吗?
- 我们重现埃氏筛选的过程:
- 第一层循环 i,需要选择从 1 到 √n 的因子;
- 第二层循环 j,表示 i*j 都是非素数,筛出来;
- 举例说明:20
i=2:筛出 2 4 6 8 10 12 14 16 18 20
i=3:筛出 3 6 9 12 15 18
i=4:合数,不用筛
i=5:5> √ 20,结束了。 - 样例分析:其中 6 12 18 都被重复筛选了。
- 以下是线性筛选的思路:
- 合数可能有多个因子,但肯定有最小的质数因子,所以只要被第一个因子找到,就不需要再找了;
- 当前的 i,只是与已经找到的质数进行乘法运算: i * a[ j ] | (1<=j<=x );
- 如果当前的 i,是合数,那么他的最小质因子与自身的乘积,就是下一个边界,避免接下来的重复;
- 具体要证明:1)是否能全部合数都筛到;2)是否不会重复;
- 以下是线晒的时间复杂度展示:
代码:
//求1-n的素数:线性筛选
//时间复杂度:O(n)
#include<bits/stdc++.h>
bool f[100000005];//0表示素数,1表示合数
int a[100000005];//10W以内的素数表
int main()
{
int n,ans=0,x=0;
memset(f,0,sizeof(f));//将f数组初始化为0:素数
scanf("%d",&n);
f[1]=1;//1不是素数
for(int i=2;i<=n;i++)
{
if(f[i]==0) a[++x]=i;//没被筛出,肯定是素数
for(int j=1;i*a[j]<=n;j++)
{
//i不管是合数还是素数,都负责与“前x个素数”相乘
f[i*a[j]]=1;
ans++;
//如果 i 是合数,只要包含了这个最小的因子,则结束
if(i%a[j]==0) break;
}
}
// for(int i=1;i<=x;i++)//直接查表,完美!
// {
// printf("%d ",a[i]);
// }
//是打表部分
printf("当前 n =%d: 筛选次数是:%d",n,ans);
return 0;
}