素数的一般筛法与线性筛法
来源:互联网 发布:中国移动的4g网络制式 编辑:程序博客网 时间:2024/06/05 17:29
如果不是对大素数进行判断的话,素数的打表是一个经常涉及到的内容。现在说下一般的筛法和优化后的“线性筛法”
一般的筛法(来自百度,已经知道的人可以跳过这一段):
用筛法求素数的基本思想是:把从1开始的、某一范围内的正整数从小到大顺序排列, 1不是素数,首先把它筛掉。剩下的数中选择最小的数是素数,然后去掉它的倍数。依次类推,直到筛子为空时结束。
如:
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30
1不是素数,去掉。剩下的数中2最小,是素数,去掉2的倍数,余下的数是:
3 5 7 9 11 13 15 17 19 21 23 25 27 29
剩下的数中3最小,是素数,去掉3的倍数,如此下去直到所有的数都被筛完,求出的素数为:
2 3 5 7 11 13 17 19 23 29
代码:
乍一看,很多人认为这种筛法效率应该不差,和普通的试除法相比确实运行速度上要快很多。
但是大家可以试一下,设置maxn = 2e+8,在我的机器上要运行36s。
为什么对于稍微大些的数据,筛法还是无能为力呢?因为在程序运行时,会产生大量重复计算。
比如拿15 来说 在将3 判定素数时,将15判为合数,而在将5判定为素数,又一次将15判定为合数。很容易理解,在程序运行时,会产生大量不必要的计算。
下面说下优化后的筛法:
<a target=_blank href="http://blog.csdn.net/dinosoft/article/details/5829550">一般筛法求素数+快速线性筛法求素数</a>
线性筛法参考了上述博文 含证明
代码:
这段代码实际上用到了唯一因子分解定理,即合数a仅能以一种方式写成如下形式:
a = p1^e1 * p2^e2 * p3^e3 *....*pn^en (p1 < p2 < ... < pn)
可能很多人认为这显然成立,但还是有实际应用价值。
程序:每个数进入循环时判断是否是素数。之后进行筛除(除去合数)
和一般的筛法不同的是,它并不是将数的所有整数倍全部筛去,程序只筛除不大于 其最小质因数 与 i 的乘积
对于循环时的i来说,可以分为两种情况:
I.i是素数 II.i不是素数
1.若i是素数,那么 i * (小于 i 的素数)得到的合数在之前肯定没有筛去,所以不会发生重复筛除。
2.若i是合数,假设i = p1^e1 * p2^e2 * p3^e3 *....*pk^ek,那么只筛去小于p1 的质数与 i 的乘积这样就避免了重复筛除。 简单证明:设这个数(将要筛除的数)为 x=p1*p2*...*pn, pi都是素数(1<=i<=n) , pi<=pj ( i<=j ) 第一个能满足筛除 x 的数 y 必然为 y=p2*p3...*pn(p2可以与p1相等或不等),而且满足条件的 y 有且只有一个。所以不会重复删除。 这样是否能筛除全部的合数? 参看<a target=_blank href="http://blog.csdn.net/dinosoft/article/details/5829550">http://blog.csdn.net/dinosoft/article/details/5829550</a>
这样优化后的算法,设置maxn = 2e+8时,11s就能得出结果
()
代码:
#include <iostream>#include <stdio.h>#include <stdlib.h>#include <memory.h>using namespace std;const int maxn = 2e+8;bool prime[maxn];int ans[maxn];int cnt = 0;typedef long long LL;void make_prime(){ memset(prime,true,sizeof(prime)); prime[0] = prime[1] = false; for(LL i = 2; i < maxn; i++) { if(prime[i]) { ans[++cnt] = i; //为什么k从i*i开始?而(i - 1) * i 以及之前的项为什么不筛? //目前只对(i - 1)*i这一项进行说明,其他的应该类似 //分两种情况:1.(i - 1)为素数,那么(i - 1) * i 在对(i - 1)筛的时候就已经筛过了 //2.(i - 1)为合数,那么一定能找到小于等于sqrt(i - 1)的素数j,j在筛选的时候能够将(i - 1)筛去, //(举一个特例,筛去5的倍数时从25开始,而20是一个合数,20 = 4 * 5,所以在筛2的倍数时将4筛去,同样4*5在筛2的时候一定会被筛去) for(LL k = i * i; k < maxn; k += i) prime[k] = false; } } return;}int main(){ freopen("out.txt","w",stdout); make_prime(); for(int i = 1; i <= cnt; i++) cout<<ans[i]<<endl; int a = 13; return 0;}
乍一看,很多人认为这种筛法效率应该不差,和普通的试除法相比确实运行速度上要快很多。
但是大家可以试一下,设置maxn = 2e+8,在我的机器上要运行36s。
为什么对于稍微大些的数据,筛法还是无能为力呢?因为在程序运行时,会产生大量重复计算。
比如拿15 来说 在将3 判定素数时,将15判为合数,而在将5判定为素数,又一次将15判定为合数。很容易理解,在程序运行时,会产生大量不必要的计算。
下面说下优化后的筛法:
<a target=_blank href="http://blog.csdn.net/dinosoft/article/details/5829550">一般筛法求素数+快速线性筛法求素数</a>
线性筛法参考了上述博文 含证明
代码:
#include <iostream>#include <stdio.h>#include <stdlib.h>#include <memory.h>using namespace std;typedef long long LL;const LL maxn = 2e+8;int prime[maxn] = {0};//基于0LL num_prime = 0;bool isNotPrime[maxn] = {1,1};//除了0,1外其余都是素数int main(){ freopen("out2.txt","w",stdout); for(LL i = 2;i < maxn;i++)//依次枚举各个数字 { if(!isNotPrime[i]) prime[num_prime++] = i; //进行线性筛除 for(LL j = 0;j < num_prime && i * prime[j] < maxn;j++) { isNotPrime[i * prime[j]] = 1;//把小于 i 的素数 和 i 的乘积置为合数这里可以分为两种情况 1.i是素数 2.i不是素数 if(!(i % prime[j]))//只筛除不大于 其最小质因数 与 i 的乘积 break; } } for(LL i = 0;i < num_prime;i++) { if(0==i % 50) cout<<endl; cout<<prime[i]<<" "; } return 0;}
这段代码实际上用到了唯一因子分解定理,即合数a仅能以一种方式写成如下形式:
a = p1^e1 * p2^e2 * p3^e3 *....*pn^en (p1 < p2 < ... < pn)
可能很多人认为这显然成立,但还是有实际应用价值。
程序:每个数进入循环时判断是否是素数。之后进行筛除(除去合数)
和一般的筛法不同的是,它并不是将数的所有整数倍全部筛去,程序只筛除不大于 其最小质因数 与 i 的乘积
对于循环时的i来说,可以分为两种情况:
I.i是素数 II.i不是素数
1.若i是素数,那么 i * (小于 i 的素数)得到的合数在之前肯定没有筛去,所以不会发生重复筛除。
2.若i是合数,假设i = p1^e1 * p2^e2 * p3^e3 *....*pk^ek,那么只筛去小于p1 的质数与 i 的乘积这样就避免了重复筛除。 简单证明:设这个数(将要筛除的数)为 x=p1*p2*...*pn, pi都是素数(1<=i<=n) , pi<=pj ( i<=j ) 第一个能满足筛除 x 的数 y 必然为 y=p2*p3...*pn(p2可以与p1相等或不等),而且满足条件的 y 有且只有一个。所以不会重复删除。 这样是否能筛除全部的合数? 参看<a target=_blank href="http://blog.csdn.net/dinosoft/article/details/5829550">http://blog.csdn.net/dinosoft/article/details/5829550</a>
这样优化后的算法,设置maxn = 2e+8时,11s就能得出结果
()
0 0
- 素数的一般筛法与线性筛法
- 筛法求素数 (一般的线性筛法)
- 求素数: 一般线性筛法 + 快速线性筛法
- 一般筛法和快速线性筛法求素数 求素数的一点总结
- 线性素数筛法
- 线性筛素数法
- 短小精悍的线性时间素数筛法
- 素数线性筛法的原理
- 短小精悍的线性时间素数筛法
- 短小精悍的线性时间素数筛法
- 关于素数的线性筛法
- 线性素数筛法模板
- 素数问题-线性筛法
- 一般线性筛法求素数与快速线性筛法求素数模板
- POJ 2262 Goldbach's Conjecture (求解素数的一般筛和线性筛)
- #C语言#关于求素数的思路(一般筛法到线性筛)
- 【转】短小精悍的线性时间素数筛法
- 短小精悍的线性时间素数筛法(转)
- asdas
- Oracle - 查看用户所在的表空间,表,视图,索引。。。。
- hnu 13073 Ternarian Weights
- 简单函数的返回
- 用SetStdHandle重定向golang的panic信息
- 素数的一般筛法与线性筛法
- TotoiseSVN的基本使用方法
- C++中的函数指针和函数对象总结
- 排序算法小结
- Oracle - 创建表空间,序列
- js选择器
- 【代码实现】PHP导入Excel和导出数据为Excel文件
- arcgis Flex Map控件
- iOS block的用法