一般方法
原理概述:
1不是质数也不是合数,特殊处理;
从2枚举到 √x,若有能除尽的数直接返回x不是素数
Q:为什么枚举到√x?
若m整除n(其中n>根号m)则m=n*k。 若m不整除从1除到√m的数它就不可能整除根号m后面的数。
如果根号m有小于√m的因子X,那么N必定有大于√m的因子Y与X对应。 而且X *Y=m
(来源:百度)
实现说明:
略
bool isPrime_usual(int x)
{
if(x==1)
return false;
for(int i=2; i*i<=x; i++)
if(x%i==0)
return false;
return true;
}
埃拉托斯特尼筛法(埃氏筛)
原理概述:
从最小的素数2开始,2…3…5…将这些数的倍数标为合数。
实现说明:
首先要有一个数组vis,用来标记那些数是素数,所得结果也存在这个数组,并都初始化为true(即默认所有数都是素数)
从2开始枚举,若vis[i]==true,则用一个循环去将vis[i]的倍数都标记为非素数。个人感受j从i * i开始好一些,有一些从j=2*i开始会降低效率(重复筛)。
bool vis[Maxn];
void isPrinme_era()
{
memset(vis,true,sizeof(vis));
for(int i=2; i<maxn; i++)
{
if(vis)
for(int j=i*i; j<Maxn; j+=i)
vis[j]=false;
}
}
线性筛
原理概述:
在普通筛的基础上,筛数时只用该合数最小的因子筛掉这个数。
实现说明:
首先需要两个数组p和vis,p用来存素数,vis用来标记素数。
从2开始,将i录入数组p,与埃氏筛一样,再用一个循环去将i的倍数标记为非素数,不同点在于,每一个j循环标记只标记一部分,剩下的让后面的i去标记,这样就避免了重复标记。
举个例子,当i=6时,cnt=3,p数组中存有2 3 5.此时,标记完vis[26=12]=false即退出j循环不去标记vis[36=18]-flase,等i=9时,vis[2*9=18]=false去标记,
至于为什么判断条件是i%p[j]==0,若满足条件的话,i必能拆成i=p[j]*k的形式,这就说明后面必然有更大的i与p[j]相乘能得当前的i *p[j+1].
比如,6=2 *3,而当前3 *6=18 说明18必含因子2然后2 *i=18,这个i绝对大于6.
bool vis[Maxn];
void isPrime_linear()
{
int cnt=0;
int p[Maxn];
memset(vis,true,sizeof(vis));
for(int i=2; i<=Maxn; i++)
{
if(vis)
p[cnt++]=i;
for(int j=0; j<cne&&i*p[j]<maxn; j++)
{
vis[i*p[j]=false;
if(i%p[j]==0)
break;
}
}
}
小结: 单比效率线性筛是最快的时间复杂度无限接近O(n),第一种方法较方便,代码量少,但每次只能进行单个数的判断。
来源:CSDN
作者:seclued soul
链接:https://blog.csdn.net/qq_43811051/article/details/104257147