算法笔记--素数筛(朴素筛,埃式筛,欧拉筛)

本文介绍了素数筛的三种常见算法:朴素筛、埃氏筛和欧拉筛。朴素筛时间复杂度高,不推荐使用;埃氏筛虽然效率稍好,但存在冗余操作;欧拉筛通过优化避免了重复筛选,达到较高的效率。对于大范围素数筛选,通常使用欧拉筛。
摘要由CSDN通过智能技术生成

素数

素数也叫质数,是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。如2 , 3 , 5 , 7 , 11等。

素数筛

素数筛即筛选出1~n内的素数的方法,这里介绍三种

1.朴素筛

由上面的概念得,我们可以想到引入一个从1到它本身的for循环,只要中间有取余为0,那么它就不是素数。

#define MAX 100000
int prime[MAX];
int x=0;
void psshai(int n)
{
	for(int i=2;i<=n;i++)//因为1不是素数,从2开始遍历
	{	
		int flag=0;//标记为0,假设该数是素数
		for(int j=2;j<i;j++)//取2~i-1判断(优化一下:i也可以换成根号i,但这样只稍微增加了一点速度)
		{
			if(i%j==0)//取余为0,该数不是素数
			{
				flag=1;//标记解除
				break;
			}
		}
		if(flag==0)//标记未解除,说明该数是素数
			prime[++x]=i;//存储
	}
}

这种算法就是暴力枚举,优化后时间复杂度O(n*sqrt(n))。不推荐,太慢。

2.埃氏筛

我们知道最小的素数是2,埃氏筛就是从2开始,在判断该数是否为素数的同时将该数的倍数筛去,因为一个数(从2开始)的倍数一定不是素数,注意一下范围别超过n就行

#define MAX 100000
bool Isprime[MAX];
void asshai(int n)
{
	for(int i=2;i<=n;i++)
		Isprime[i]=true;//初始化2~n都是素数
	for(int i=2;i<=n;i++)//遍历
	{
		if(Isprime[i])//如果是素数
		{
			for(int j=2;i*j<=n;j++)//把是i的j倍的数都去掉,注意范围到n
			{
				Isprime[i*j]=false;
			}
		}
	}
}

这种算法的时间复杂度是O(nlogn),但是我们会发现里面的一些操作有点冗余。比如数字6,它既是2的3倍又是3的2倍,这样在筛选的时候被筛出去两次,其实是在重复的做无用功。即使这样,这种算法一般的题也能用

3.欧拉筛

欧拉筛就是对埃氏筛的优化了,即使一个数仅被一次筛除

#define MAX 100000
bool vis[MAX];//默认都是false
int prime[MAX];
int x=0;
void olshai(int n)
{
	for(int i=2;i<=n;i++)
		vis[i]=true;//初始化2~n都是素数
	for(int i=2;i<=n;i++)
	{
		if(vis[i])//如果是素数
			prime[++x]=i;//存储在prime中
		for(int j=1;j<=x && i*prime[j]<=n;j++)//核心部分,下文详细讲
		{
			vis[i*prime[j]]=false;
			if(i%prime[j]==0)
				break;
		}
	}
}

在这里插入图片描述
1、当 i 是素数时,存储素数,并剔除 i 的整数倍,其中整数应为素数且小于等于前 i 个数中已知最大的素数,注意乘积小于等于n
2、当 i 不为素数,剔除 i 的整数倍,在注意上面(其中整数应为素数且小于等于前 i 个数中已知最大的素数,注意乘积小于等于n)要求的同时判断 i % prime[j],如果整除则退出
i % prime[j]这一步就是对埃氏筛的优化,举个例子理解一下
如果没有这一步,那么当i=9时,prime【1】=2,prime【2】=3,prime【3】=5,prime【4】=7;本来是当 j=2 的时候跳出循环,但是却没有,那么j = 3时 9 * 5 =45,该统计在 i = 15 的时候也会统计,也就是当 i = 15 时候,j = 2 ,prime【2】 = 3,也统计了 3 * 15 = 45 ,明显,重复统计,所以要及时break。
欧拉筛的时间复杂度是O(n),所以普遍使用欧拉筛来筛选素数


当然如果区间非常非常大的时候,就要用到区间筛用偏移来筛选了,这种情况少见,就不多介绍了,感兴趣可以继续研究~~(本人能力有限)~~
本篇对这篇博客(写的很好,通俗易懂,点击查看哦)
有所借鉴。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值