素数筛法及其优化 FLY

找素数筛选法,就这个看懂了,笑哭笑哭

今天试了一下素数筛法
要求1-100000范围内的素数,如果用自定义函数挨个求,对于大范围的求素数会非常耗时。复杂度为O(n * sqrt(n)),所以可以用素数筛法来求大范围内的素数
说一下比较暴力的思路:
开一个标记数组,全部初始化为true,0、1不是素数,直接从数组里划掉。
从未遍历过的最小的标记为 true 的位置开始,所有是这个位置的下标的倍数的位置都标记为 false。
从一开始:
最小的标记为 true 的位置是 2 ,从 2 开始,凡是 2 的倍数、且小于 100000 的,全部标记为 false 。
再找 2 以后的、是 true 的下一位数,是 3。
从 3 开始,凡是3的倍数、且小于100000的,全部标记为false。
再找 3 以后的、标记为 true 的下一位数,是 5。
从 5 开始,凡是 5 的倍数、且小于 100000 的,全部标记为 false 。
这样循环,直到开始的位置大于 100000 ,退出循环。
这样,所有标记为 TRUE 的元素的下标全是素数。
贴上代码

bool isprime[1010];
memset(isprime, true, sizeof(isprime));
for (int i = 2; i <= 1000; i++)
{
    if (isprime[i])
        for (long long j = 2; j * i <= 1000; j++)
            isprime[j * i] = false;
}

然而这样做会有重复的标记为 false 的过程,想要提高效率,还可以采用下面这种办法,在对大数据处理的时候会有明显的优势。
这段代码的前提是:默认所有大于 2 的偶数全都不是素数,所以在算法开始前有一个 for 循环先把这些数标记为了 false 。

bool isprime[1000010];
memset(isprime, true, sizeof(isprime));
for (int i = 4; i <= 1000000; i += 2) // 所有大于 2 的偶数全都不是素数,首先划掉
    isprime[i] = false;
for (int i = 3; i <= 1000000; i++)
{
    if (isprime[i])
        for (long long j = i * i; j <= 1000000; j += i + i)
            isprime[j] = false;
}                                                                             //这一块我感觉应该从3开始,因为2的倍数都进行标记了,再来就重了原文是从2开始

解释一下 for (long long j = i * i; j <= 1000000; j += i + i) 这个循环
首先从 j += i + i 说起:
首先在上面已经把所有的偶数位全部标记为 false,所以,当 isprime[i] 能进入在这个 for 循环上面 if 的时候,i 一定是个奇数。j 的起始值是 i * i 所以,起始值也一定是个奇数。
所以 j 要一下加两个 i ,因为 j 加上一个 i 后一定是个偶数。
再说起始值为什么为 i * i :
像上面所说, i 是个奇数。
对于 i * (i - 1 - 2k) ,因为 i - 1 是个偶数,所以 i - 1 - 2k 一定是个偶数,所以 i * (i - 1 - 2k) 一定是个偶数,其所在位置一定标为false 。
对于i * (i - 2k) (k = 1, 2, 3…)i - 2k 一定是个奇数,对于任意的i * (i - 2k),一定有这样一个循环标记过 i * (i - 2k) 这个位置:for(long long j=(i - 2k) * (i - 2k); j <= 1000000; j += i + i),所以i * (i - 2k)一定是一个以前标记为 false 的位置。
综上,i * (i - 1 - 2k) 与i * (i - 2k) (k = 1, 2, 3…)一定都是被标记过 false 的位置,所以直接略过,从 i * i 开始。
————————————————
版权声明:本文为CSDN博主「life_bre」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/sdutstudent/article/details/53783051

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值