打赏

线性筛法求素数

说到求素数,其实自己刚学C++那时也遇到过这种问题,如果你那时候叫我写个求1~100以内的素数的程序,我会毫不犹豫的这样写(然后被一堆大佬疯狂吊打qwq):

#include <iostream>
using namespace std;

bool prime(int x){
    if(x<=1) return false;
    for(int i=2;i*i<=x;i++){
        if(x%i==0) return false;
    }
    return true;
}
int main(){  //求1~100以内的素数
    for(int i=1;i<=100;i++)
        if(prime(i)) cout << i << ' ';
    return 0;
}

其实这并不算筛法,而且时间复杂度非常高,该算法比较少用,但优点是占用空间较少
但如果题目的数据范围一大起来,这种算法肯定挂 (这也是自己被大佬们疯狂吊打的原因吧)


埃式筛

第一种算法的时间复杂度太高了,下面介绍一种真正的筛法,即埃式筛,而且时间复杂度还比上面介绍的低 (这不废话吗,比上面的高那还用介绍吗?)

#include <iostream>
using namespace std;

bool book[20005];
int main(){  //求1~100以内的素数
    for(int i=2;i<=100;i++)
        if(!book[i]){
            for(int j=i+i;j<=100;j+=i)
                book[j]=1;
        }
    for(int i=2;i<=100;i++)
        if(!book[i]) cout << i;
    return 0;
}

以上代码的思想是:对于不超过n的素数p,删除2p,3p,4p…,当处理完所有的数之后,还没有被删除的数就都是素数。 怎么样,是不是比第一种方法快很多? 但是,仔细分析我们就会发现,这种筛法还是存在一个问题:重复筛,比如当i为2的时候,3*i是等于6的,也就是说,当i=2的时候6就被筛掉了,但是i=3的时候,2*i也等于6,我们会发现6又被筛了一次,所以这种筛法还是达不到我们的要求。

线性筛

现在轮到今天的主角登场了!这就是线性筛!那么线性筛到底有什么好的呢?

先来看看线性筛的思路:
其实,线性筛就是埃式筛的升级版,它解决了埃式筛遗留的问题:重复筛。它让每个合数只被他的最小质因子筛一遍,它的时间复杂度接近于O(N)。(这么好的算法,简直是AK IOI必备啊)

上代码:

#include <iostream>
using namespace std;

bool book[20005];
int prime[20005],pos,i,j;
int main(){  //求1~100以内的素数
    for(i=2;i<=100;i++){
        if(!book[i]) prime[++pos]=i;
        for(j=1;j<=pos;j++){
            if(i*prime[j] > 100) break;
            book[i*prime[j]]=1;
            if(i%prime[j]==0) break;
        }
    }
    for(int i=1;i<=pos;i++)
        cout << prime[pos];
    return 0;
}

现在来逐行代码解析:
现在来看 if(!book[i]) prime[++pos]=i; ,这段代码的作用是判断当前数是否被筛过(如果没筛过,即book[i]=0,那么这个数就是素数,所以就要往prime的尾部添加这个数字)。
if(i*prime[j] > 100) break; 这段代码的作用是控制筛的范围
book[i*prime[j]]=1; 则是把当前的数筛掉

if(i%prime[j]==0) break;接下来重点解析这句话,他就是避免重复筛的关键!

当i是prime[j]的整数倍时,说明 i * prime[j+1] 是 prime[j] 的整数倍,不需要现在筛出,因为在之后筛除过程中i * prime[j+1] 这个合数一定会被prime[j]筛除,prime[j]之后的所有素数同理,所以break跳出循环。




参考文章:https://blog.csdn.net/FeilingGong/article/details/83660779

posted @ 2020-02-14 13:52  _Return  阅读(87)  评论(5编辑  收藏