出处
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、每个数都没有被重复地删掉