您的位置:首页 > 其它

筛法求素数;终于找到一篇一看即会的BLOG了;

2010-04-30 12:39 295 查看
#include <iostream>
#include <vector>
using namespace std;

#define KEPT true
#define DELETED false

int main()
{
//筛法求素数,输入范围: n
int range;
cin>>range;
//挑选小于n的奇数记录入数组,因为偶数一定不是素数,下标cnt的元素对应奇数2*cnt+1,并初始化这些奇数未筛
vector<bool> sieve;
for(int cnt=0;cnt+cnt+3<=range;++cnt)
{
sieve.push_back(KEPT);
}

int size=sieve.size();
int count=0;
int increase;
for(int i=0;i<size;++i)//用每一个未被筛的素数筛选其后奇数倍自身的奇数
{
if(sieve[i]==KEPT)
{
++count;
increase=i+i+3;
for(int j=increase+i;j<size;j+=increase)
{
sieve[j]=DELETED;// 这里完成对奇数倍自身的元素筛选
}
}
}
//打印结果
for(int cnt=0,num=0;cnt<size;++cnt)
{
if(sieve[cnt]==KEPT)
{
cout<<cnt+cnt+3<<" ";
++num;
if(num%6==0)
{
num=0;
cout<<endl;
}
}
}
}


如果整数 n ≠ 0,±1。如果除了显然因数 ±1 和 ±n 以外,n没有其他因数,那么 n 叫做素数。如:2,3,5,7是素数,4,6,10,15是合数。

  根据素数的性质,有这样的定理:1、设 n 是一个正合数,p 是 n 的一个大于1的最小正因数,则 p 一定是素数。2、设 n 是一个正整数,如果对所有的素数 p ≤ √n,都有 p 不整除 n,则 n 一定是素数。

  根据两条定理,可以得到寻找素数的群定性方法,通常叫做 埃拉托斯散筛法。
  筛法具体描述如下:对于任意给定的整数 N ,要求出所有不超过 N 的素数。列出 N 个整数,从中删除小于等于√n的所有素数p1, …, pk的倍数。然后依次删除余下的整数(不包括1)就是所要求的不超过 N 的素数。
  如果让你用筛法求出 2 到 某个数 之间的所有素数,如何用代码实现呢?

  思路:用一个数组x[0], x[1], …来存储3,5,7,11…這些奇数,因此,x[i]中所有存储的数就是2i+3。将所有元素初始状态设置为未筛除,然后依次去掉其中的合数。

  现在考虑如何删除合数。从x[0],x[1]…如果x[i]未被筛出,则其为质数,删除其所有倍数,依次往下走。但x[i]中储存的值是2i+3,而2i+3的倍数在数组中的什么地方呢?因为数组中全部是奇数,所以2i+3的倍数可以表示为(2n+1)(2i+3),根据(2n+1)(2i+3) = 2n(2i+3)+2i+3 = 2[n(2i+3)+i]+3,知道x[i]对应的数(即2i+3)的倍数的位置为n(2i+3)+i。当n=1是,值为(2i+3)+i,当n=2时,值为(2i+3)+i+(2i+3), 依次类推,用(2i+3)+i作为初值,删掉对应的x[],再加上2i+3,删掉对应的数,直到无数可删。因为最后的一个素数可以表示为2N+3,所以筛法求出的为2到N之间的素数。

 

其实算法简单,只不过化简了一个公式。利用了位置之间的关系。但是叙述起来比较麻烦。因为偶数不会是素数,所以本算法中,一开始存储的待筛数组全部为奇数。其实还可以在最初状态下,不考虑3的倍数,5的倍数等等。这个筛法可以再改进的!

 

原文:http://blog.okkey.net/907.html/comment-page-1
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  blog 存储 算法 include