素数及筛法

素数简介

素数(prime number)又称质数,有无限个。
素数定义为在大于1的自然数中,除了1和它本身以外不再有其他因数。

接下来介绍几种判断素数的方法:

问法1:给定一个数n,判断n是不是素数

一、暴力枚举

枚举2~n-1分别当做除数,判断是否能整除,如果某个数能把n整除,那么就说明n不是素数,如果所有都不能整除,那么n就是素数。
注:n=1或n=2时需要特判

详见代码:

bool work(int n)
{
    if(n==1)return false;
    if(n==2)return true;
    for(int i=2;i<=n-1;i++)
    {
        if(n%i==0)return false;
    }
    return true;
}

然而这样会很慢......

二、优化过的暴力算法

由于n至少会有一个约数在sqrt(n)中,所以我们可以直接枚举从2~sqrt(n),这样便会快不少。

详见代码:

bool work(int n)
{
    if(n==1)return false;
    if(n==2)return true;
    for(int i=2;i*i<=n;i++)//这里也可以写成i<=sqrt(n)
    {
        if(n%i==0)return false;
    }
    return true;
}

以上所说的算法只是用来判断单个素数的,但是若是要求1~n之间的素数该怎么办呢?

还是暴力?
不!
要用到一个名叫“筛法”的东东

三、埃氏筛法

由于我们知道,2的任何倍数都不可能是素数,3的任何倍数不可能是素数,5的任何倍数不可能是素数......
所以我们可以把素数的倍数全部筛掉。
详见代码:

/*
vis用来判断有没有被筛掉,
prime用来存储素数
cnt代表素数总数
*/
for(int i=2;i<=n;i++)
{
    if(vis[i]==1)continue;
    prime[++cnt]=i;
    for(int j=1;j*i<=n;j++)//筛掉素数的所有倍数
    {
        vis[j*i]=1;
    }
}

但是以12为例
12是2的倍数,被筛
12是3的倍数,被筛++
所以事实证明会有一些数被筛好多次
那要怎么做到每个数只筛一次的线性复杂度呢?

四、线性筛

线性筛,又称欧拉筛
欧拉筛法的基本思想 :在埃氏筛法的基础上,让每个合数只被它的最小质因子筛选一次,以达到不重复的目的。

/*
vis用来判断有没有被筛掉,
prime用来存储素数
cnt代表素数总数
*/
for(int i=2;i<=n;i++)
{
    if(!vis[i])prime[++cnt]=i;
    for(int j=1;j<=cnt&&i*prime[j]<=n;j++)
    {
        vis[i*prime[j]]=1;
        if(i%prime[j]==0)break;
    }
}

以上就是素数判断及筛法的总结,谢谢观看

参考文献资料:
https://www.baidu.com
https://blog.csdn.net/qq_39763472/article/details/82428602

最后打个小广告:
https://www.luogu.org/blog/hulean0319/Game-ZMXY

猜你喜欢

转载自www.cnblogs.com/hulean/p/10799277.html