线性筛法求素数
2017-11-08 17:07
218 查看
出处
http://www.cnblogs.com/grubbyskyer/p/3852421.html普通筛选法–埃拉托斯特尼筛法
先简单说一下原理:
基本思想:素数的倍数一定不是素数
实现方法:用一个长度为N+1的数组保存信息(0表示素数,1表示非素数),先假设所有的数都是素数(初始化为0),从第一个素数2开始,把2的倍数都标记为非素数(置为1),一直到大于N;然后进行下一趟,找到2后面的下一个素数3,进行同样的处理,直到最后,数组中依然为0的数即为素数。
说明:整数1特殊处理即可。
举个例子,N=20时,演示如下图:
最后数组里面还是0的就是素数了…
代码实现如下:
prime[]用来保存得到的素数 prime[] = {2,3,5,7,11,………} tot 是当前得到的素数的个数 check :0表示是素数 1表示合数
*#include<cstdio> #include<iostream> #include<cstring> using namespace std; const int M = 2000; int prime[M + 10]; int check[M]; int main() { int t = 0; memset(check,0,sizeof(check)); for(int i = 2; i <= M - 1; ++i) { if(!check[i]) { prime[t++] = i; for(int j = 2; j * i<= M - 1;++j) { check[j * i] = 1; } } } cout << t << endl; for(int i = 0; i <= t - 1; ++i) { cout << prime[i] << ','; } return 0; }
此筛选法的时间复杂度是O(nloglogn) 空间复杂度是O(n)
不足之处也比较明显,手动模拟一遍就会发现,很多数被处理了不止1遍,比如6,在素数为2的时候处理1次,为3时候又标记一次,因此又造成了比较大的不必要处理…那有没有改进的办法呢…就是下面改进之后的筛法…
线性筛法–欧拉筛法
#include<cstring> #include<iostream> using namespace std; const int M = 2000; int prime[M + 10]; void getprime() { memset(prime,0,sizeof(prime)); for(int i = 2; i <= M; ++i) { if(!prime[i]) { prime[++prime[0]] = i; } for(int j = 1; j <= prime[0] && i < M / prime[j]; ++j) { prime[i * prime[j]] = 1; if(i % prime[j] == 0) // 保证了每个数只被筛一次 break; } } } int main() { getprime(); cout << prime[0] << endl; for(int i = 1; i <= prime[0] - 1; ++i) { cout << prime[i] << ','; } return 0; }
精华就在于红色标注那两处,它们保证每个合数只会被它的最小质因数筛去,因此每个数只会被标记一次,所以时间复杂度是O(n)
此过程中保证了两点:
1、合数一定被干掉了…
2、每个数都没有被重复地删掉
扩展博客:http://suno.cnblogs.com/
相关文章推荐
- 【线性筛】【筛法求素数】【约数个数定理】URAL - 2070 - Interesting Numbers
- 线性筛法求素数【Template】
- 【线性筛】【筛法求素数】【素数判定】URAL - 2102 - Michael and Cryptography
- HDU 3823 线性筛法求素数+暴力
- 欧拉线性筛法求素数(顺便实现欧拉函数的求值)
- 线性筛法求素数
- {模板}线性筛法求素数表
- Sicily 1089.Farey Sequence[线性筛法求素数]
- 线性筛法求素数的原理与实现
- 一般线性筛法求素数与快速线性筛法求素数模板
- 线性筛法求素数+欧拉函数+矩阵快速幂+快速求第n个斐波那契数
- 线性筛法求素数
- 线性筛法求素数表
- 线性筛法求素数
- {模板}线性筛法求素数
- 线性筛法求素数
- 筛法求素数&线性筛法求素数
- 线性筛法求素数模板
- 线性筛法求素数
- 线性筛法求素数的原理与实现