欧拉筛法实现素数表的快速筛取

引子:
我现在想知道1——1e8的范围内有多少个素数(质数),有什么方法?
朴素法,对于每一个数n,我们判断它是否是素数
像这样:

bool check(int curr)
{
    int i;
    for(i = 2; i < sqrt(curr)+1; ++i)
    {
        if(curr % i == 0) return false;
    }
    return true;
}

对于每一个数,我们最多需要sqrt(n)次便可以判定出它是素数还是合数。
太慢了!这个时间复杂度已经可以飞出天际了。


我们需要一种快速的方法筛取素数。
我们观察素数和合数最大的不同——合数有多个因数(除了1与自身),而素数不行。那么当我们得知对于int x,2 * x ,3 * x……便一定都是合数
看来这个效率很高,但是还是不够快。因为会出现判断重复

那么我们便使用欧拉筛法来筛取素数。
前文的方法做了什么无用功?例如20的判断,我们在2,4,5,10的时候都去判定了一次,而欧拉筛法可以保证20 只被判定1次
如何保证?


先放出源代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 10000005;

int n, x[maxn], pri[maxn/10], tot, curr, num;//m以内的质数不会m/10个,不放心 || m很小的话可以再开大一点

int main()
{
    //freopen("test.in", "r", stdin);
    scanf("%d%d", &n, &num);
    x[1] = 1;
    for(int i = 2; i != n+1; ++i)
    {
        if(!x[i])
        {
            pri[tot++] = i; //如果一个数是合数那么它一定会在之前被判定出来,故剩下的一定是质数
        }
        for(int j = 0; j != tot; ++j)//当前的所有质数
        {
            curr = pri[j]*i;//一定是合数
            if(curr > n)    break;//超出范围
            x[curr] = 1;//置为合数
            if(i % pri[j] == 0)    break;//重点
        }
    }
    fclose(stdin);
    return 0;
}

重点代码:

if(i % pri[j] == 0)    break;

要说保证某数不被重复判断,关键就在这行代码上。
满足上式时,i是pri[j]的倍数,那么对于后面的pri[k]来说,i * pri[k]就可以被分解为pri[j] * (i / pri[j] *pri[k]),而该数在之前i == pri[j]的时候已经出现过,于是就重复了。直接退出,避免了重复判定


欧拉筛法固然快,但是也有适用条件,例如求(n, n + 10)中的素数个数的时候,它就明显慢了。由于必须从1开始,所以欧拉筛法的用处在于直接打表而不是求某一段区间。对于这种问题,朴素法未尝不可

欧拉筛法的原理分析至此结束。
箜瑟_qi 2017.04.10 00:43

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值