素数筛【埃筛,欧拉筛(线性筛)】

素数筛

转载:https://blog.csdn.net/dy416524/article/details/86431057
枚举所有小于数,看是否它能整除其他自然数,但实际上只需要枚举根号次。

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

•埃氏筛:做法其实很简单,首先将2到n范围内的整数写下来,其中2是最小的素数。将表中所有的2的倍数划去,表中剩下的最小的数字就是3,他不能被更小的数整除,所以3是素数。再将表中所有的3的倍数划去……以此类推,如果表中剩余的最小的数是m,那么m就是素数。然后将表中所有m的倍数划去,像这样反复操作,就能依次枚举n以内的素数,这样的时间复杂度是O(nloglogn)。

•欧拉筛:欧拉筛法的基本思想 :在埃氏筛法的基础上,让每个合数只被它的最小质因子筛选一次,以达到不重复的目的。其他复杂度(O(n)).


#include 
#include 
using namespace std;
bool Is_prime(int n)//普通判断素数
{
    for(int i=1;i*i<=n;++i)
    {
        if(n%i==0) return false;
    }
    return true;
}
#define maxn 10000000
bool vis[maxn];
int prime[maxn],x;
void isprime(int n) //埃氏筛
{
    for(int i=2;i<=n;i++)
    {
        if(!vis[i]) prime[x++]=i;
        for(int j=2;j*i<=n;j++)
        {
            vis[i*j]=true;
        }
    }
}
void oulasai(int n)  //欧拉筛
{
    for(int i=2;i<=n;i++)
    {
        if(!vis[i]) prime[x++]=i;
        for(int j=0;j<x;j++)
        {
            if(i*prime[j]>n) break;
            vis[i*prime[j]]=true;
            if(i%prime[j]==0) break;
        }
    }
}
int main()
{
    int n;
    scanf("%d",&n);
    oulasai(n);
    for(int i=0;i<x;i++)
        printf("%d\n",prime[i]);
    return 0;
}

欧拉筛的难点就在于对if (i % prime[j] == 0)这步的理解,当i是prime[j]的整数倍时,记 m = i / prime[j],那么 i * prime[j+1] 就可以变为 (m * prime[j+1]) * prime[j],这说明 i * prime[j+1] 是 prime[j] 的整数倍,不需要再进行标记(在之后会被 prime[j] * 某个数 标记),对于 prime[j+2] 及之后的素数同理,直接跳出循环,这样就避免了重复标记。
比如我们求20以内的素数,

2 是 。排除4,2整除2,跳出;

3是。 排除6,3不整除2,继续,排除9,3整除3,跳出。

4不是,但继续执行,排除8,4整除2,跳出。

5是。 排除10,15,25;

6不是。继续执行,排除12,18,30;

可见如果4处不跳出循环,12就会被筛两次。
————————————————
版权声明:本文为CSDN博主「)NCuyALnA$Ke」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/dy416524/article/details/86431057

你可能感兴趣的:(其他)