筛素数算法——线性筛素数算法

Posted chenxiaoran666

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了筛素数算法——线性筛素数算法相关的知识,希望对你有一定的参考价值。

前言

线性筛是筛素数一种比较常用的方法(实际上,它的用途含有很多,如筛(mu,phi)等玄学的函数)。它的时间复杂度近似于(O(n))


代码(代码后面有解析)

#include<bits/stdc++.h>
using namespace std;
int n;
map<int,int> Is_Prime;//保存每一个数是否为质数
vector<int> Prime;//保存全部质数
int main()
{
    scanf("%d",&n);//筛选2~n内的质数
    for(int i=2;i<=n;i++) Is_Prime[i]=1;//先默认全部都是质数
    for(int i=2;i<=n;i++)
    {
        if(Is_Prime[i]) Prime.push_back(i);//如果这个数是质数,就将其保存下来
        for(int j=0;j<Prime.size();j++)//将这个数与已有的质数进行操作
        {
            Is_Prime[i*Prime[j]]=0;//将这个数与该质数的积标记为非质数
            if(!(i%Prime[j])) break;//如果当前数是该质数的倍数,就退出循环(这个在后面会进行解释)
        }
    }
    //以下为输出部分
    printf("%d
",Prime.size());
    for(int i=0;i<Prime.size();i++) printf("%d ",Prime[i]);
    return 0;
}

对"if(!(i%Prime[j])) break"这个语句的解释

对于(2sim n)之间的一个整数(i),有两种可能性:

一:它是质数。则此时(Prime[j])必为(i)(一个质数只能被(1)和本身整除,而(Prime[j])不可能为(1),故(Prime[j])(i)),而(i)是刚保存下来的,必然在最末尾,即i后面没有其他可操作的数了,于是退出循环

二:它是合数。则可得(i=Prime[j]*x)(x)(2sim i)之间的一个整数),此时又有两种可能性:

1:(x)是质数。则(xge Prime[j])(若(x<Prime[j]),则在对(Prime[j])进行操作前就会对(x)进行操作并退出循环),那么(i)(Prime[j])之后的任意一个数(t)的积(i*t)都可以表示为(Prime[j]*x*t),而(x*t)是一个合数,所以在轮到对(x*t)(Prime[j])进行操作时时就可以得到(i*t),故不需要继续操作了,可以退出循环

2:(x)是合数。则(x)可以分解为(a*b)的形式(其中(a)是所能取值的数中的最小质数),那么(i=a*b*Prime[j])。对于(a)(Prime[j])的大小关系,又有两种可能性:

? ①:(a<Prime[j])。显然不可能(否则在对(Prime[j])进行操作前就会对a进行操作并退出循环)

? ②:(age Prime[j])(∵age Prime[j],∴b*Prime[j]le x),那么(i)应在对(x)进行操作就已经在对(b*Prime[j])进行操作的时候的时候被判定为非质数,自然无需再判一遍。

以上是关于筛素数算法——线性筛素数算法的主要内容,如果未能解决你的问题,请参考以下文章

线性筛素数

欧拉筛法

睡前数学一小时之线性筛素数:

线性筛法(欧拉筛法)求素数

浅谈线性素数筛

通过埃拉托色尼筛算法(C++)查找素数