素数的判断即其筛法

目录

试除法

试除法改进

埃氏筛

埃氏筛改进1

埃氏筛改进2

欧拉筛

题目链接


判断一个数是否是素数以及一个区间中素数的个数的问题,我们容易想到的是试除法。根据质数的定义,除1和它本身,没有能整除它的数,我们把这样的数称为素数质数。例如:2、3、5、7、11......等等。

试除法

bool Isprimes(int n)//判断是否为素数 
{
	if(n<=1)return false;
	for(int i=2;i<=n;i++)
		if(n%i==0)return false;
	return true;
}

其实很容易观察到我们只需要枚举到√n即可,因为因子都是成对出现的。例如28的因子:

1 28
2 14
4 7

因此,可以对试除法做出改进。

试除法改进

bool Isprimes(int n)//判断是否为素数 
{
	if(n<=1)return false;
	for(int i=2;i*i<=n;i++)//枚举到根号n即可 
		if(n%i==0)return false;
	return true;
}

当数据范围非常大的时候,试除法的时间复杂度非常高,很不好用。而埃拉托斯特尼筛法是比试除法更高效的算法。埃拉托斯特尼 (Eratosthenes) 筛法,简称埃氏筛,是一种由希腊数学家埃拉托斯特尼所提出的一种简单检定素数的 算法。为了得到自然数 n 以内的全部素数,必须把不大于根号 n 的所有素数的倍数剔除,剩下的就是素数。给出要筛数值的范围 n,找出以内的素数。先用 2 去筛,即把 2 留下,把 2 的倍数剔 除掉;再用下一个质数,也就是 3 筛,把 3 留下,把 3 的倍数剔 除掉;接下去用下一个质数 5 筛,把 5 留下,把 5 的倍数剔除 掉;不断重复下去...其时间复杂度O(nloglogn)

埃氏筛

bool st[N];//st[N]数组表示状态,为0是素数,为1不是素数 
int cnt=0;//记录当前素数的个数
int isprime[N];//存储素数的数组 
void Isprimes(int n)
{
	for(int i=2;i<=n;i++)
	{
		if(!st[i])isprime[cnt++]=i;//未标记则是素数,记录下来 
		for(int j=i*2;j<=n;j=j+i)//一个数的整数倍不是素数,有其他因子存在 
			st[j]=true;
	}
} 

j也可以从i * i开始枚举,因在此之前,比i小的已经枚举过了。

埃氏筛改进1

void Isprimes(int n)
{
	for(int i=2;i<=n;i++)
	{
		if(!st[i])isprime[cnt++]=i;//未标记则是素数,记录下来 
		for(int j=i*i;j<=n;j=j+i)//一个数的整数倍不是素数,有其他因子存在 
			st[j]=true;
	}
} 

也可以只枚举素数的倍数,素数的整数倍也一定不是素数,因为存在了除1和它本身以外的因子。

埃氏筛改进2

void Isprimes(int n)
{
	for(int i=2;i<=n;i++)
	{
		if(!st[i])
		{	
			isprime[cnt++]=i;//未标记则是素数,记录下来 
			for(int j=i*2;j<=n;j=j+i)//一个数的整数倍不是素数,有其他因子存在 
			st[j]=true;
		}
	}
} 

在埃氏筛中,对于6这个数字,可以发现它被2和3都枚举了一次,造成时间上的浪费,而欧拉筛就在此进行了改进:让每个合数只被它的最小质因子筛选一次 。因此每个数只被枚举一次,故欧拉筛的时间复杂度O(n)。

欧拉筛

void Isprimes(int n)
{
	for(int i=2;i<=n;i++)
	{
		if(!st[i])prime[cnt++]=i;
		for(int j=0;prime[j]<=n/i;j++)
		{
			st[prime[j]*i]=true;
			if(i%prime[j]==0)break;
		}
	}
}

题目链接

哥德巴赫猜想 

回文质数

Möbius function

你可能感兴趣的:(素数筛)