埃氏筛法及其优化

**一般而言,当数据较小时,我们求1到n的素数,可以使用双重循环暴力求解,充其次也就用个sqrt(n)优化一下,如:

#include<iostream>
#include<cmath>
using namespace std;
int main()
{
    int n,i,j,b;
    cin>>n;
    for(i=2;i<=n;++i){
        b=0;
        for(j=2;j<=sqrt(i);++j){
            if(i%j==0){b=1;break;}
        }
        if(b==0)cout<<i<<endl;
    }
    return 0;
}

不过在算法题中,往往不会有这么简单的让我们来求解,出题人经常会把数据出的很大,这个时候,身为当代好青年的我们就学要学习新东西了,比如埃氏筛**
埃拉托斯特尼筛法,简称埃氏筛或爱氏筛,是一种由希腊数学家埃拉托斯特尼所提出的一种简单检定素数的算法。要得到自然数n以内的全部素数,必须把不大于根号n的所有素数的倍数剔除,剩下的就是素数。
在这里插入图片描述
讲完原理,就直接上代码吧(狗头保命)
洛谷上的P3912题
题目描述
求 1,2,⋯,N 中素数的个数。

输入格式
一行一个整数 N。

输出格式
一行一个整数,表示素数的个数。
说明/提示
1<N<10^8
数据比较大,所以呢,一般的埃氏筛,自然也是拿不到满分啦,再次狗头保命
在这里插入图片描述

#include<iostream>
using namespace std;
bool isprime[100000005];
int main()
{
	int n,i,cnt;
	cin>>n;
    for(int i=0;i<100000005;++i)isprime[i]=true;//这里赋值为真,后面可以优化
	isprime[0]=false;isprime[1]=false;//这里,可有可无
	for(int i=2;i<=n;++i){
		if(isprime[i]){
			for(int j=i*2;j<=n;j+=i){//这里筛掉前面素数的倍数
				isprime[j]=false;
			}
		}
		if(isprime[i])++cnt;//计数即可
	}
	cout<<cnt;
	return 0;
}

这是包装成函数的情况

#include<iostream>
using namespace std;
bool isprime[100000005];
void is(int n)
{
	for(int i=0;i<100000005;++i)isprime[i]=true;
	isprime[0]=false;isprime[1]=false;
	for(int i=2;i<=n;++i){
		if(isprime[i]){
			for(int j=i*2;j<=n;j+=i){
				isprime[j]=false;
			}
		}
	}
}
int main()
{
	int n,i,cnt;
	cin>>n;
	is(n);
	for(i=1;i<=n;++i){
		if(isprime[i])++cnt;
	}
	cout<<cnt;
	return 0;
}

下面,我们对其进行优化!!!
先看完整代码:

#include<iostream>
using namespace std;
bool a[100000005];
int main()
{
	int n,i,cnt=0;
	cin>>n;
	for(int i=2;i*i<=n;++i){//其他博客写的是for(i=0;i<n;++i),这里可以改成这样,因为在前面已经筛过了
		if(a[i]==0){
			for(int j=i*i;j<=n;j+=i){//这里直接j=i*i,而不用j=i*2;因为前面有2*i,3*i,4*i....,(i-1)*i
				a[j]=1;
			}
		}
	}
	for(i=2;i<=n;++i){
		if(a[i]==0)++cnt;
	}
	cout<<cnt;
	return 0;
}

接下来我们再来分析
首先我们看

for(int i=0;i<100000005;++i)isprime[i]=true;

这里我们对其进行赋值,但是既然我们把他定义在主函数外面,那么是不是他的初值为0,而bool类型只有0和1两个值,这正好可以和true,false对应只不过需要把0当作真而已
而这里核心代码

for(int i=2;i*i<=n;++i){//其他博客写的是for(i=0;i<n;++i),这里可以改成这样,因为在前面已经筛过了
		if(a[i]==0){
			for(int j=i*i;j<=n;j+=i){//这里直接j=i*i,而不用j=i*2;因为前面有2*i,3*i,4*i....,(i-1)*i
				a[j]=1;
			}
		}
	}

优化了两个地方,一层循环和二层循环,一层循环处,i只累加到了ii<=n处,这是因为在前面的i已经将后面的数筛掉了
另一处j不等于i
2,而是j=ii,因为前面有2i,3i…,i(i-1),都筛过了,因此在此处也就不需要在重复了。
因为没有循环一部分i,因此就将这部分计数单独列出来:

for(i=2;i<=n;++i){
		if(a[i]==0)++cnt;
	}

到这里优化也就结束了,不过要想变得更强,吾辈仍需继续学习啊,因此,欧拉筛法不失为你的一种选择哦,加油少年!!!
共勉之!!!
在这里插入图片描述

  • 28
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

数学与算法

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值