线性筛法求素数

来源:互联网 发布:椭圆拟合算法 编辑:程序博客网 时间:2024/06/15 16:08

出处

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/

原创粉丝点击