三种素数筛选法详解 (转)
来源:互联网 发布:java ssm框架搭建 编辑:程序博客网 时间:2024/05/20 06:29
转自:http://tr0217.blog.163.com/blog/static/3606648020099302135503/
第一种:剔除2 3 4 5 6 … … 的倍数
在i从2开始的增一变化过程中,剔除i的倍数即j*i(j是大于等于2的自然数,j的上限是问题规模M)
为了减少重复步骤,可以每当i递增到等于第一个没有被剔除的(素)数时再剔除该数的倍数,
重复上述过程至i到达问题规模m的平方根+1
需要说明的三个问题:
假设循环到第n个数,如果该数没有被剔除,那么该数不能是前边所有数的倍数,该数更不可能是后边数的倍数,该
数就是素数。
如果该数是合数却没被剔除,那么该数能分解为两个小于该数的数的积的形式,而前边剔除的数包含了所有小于该
数的数之间的积,这是矛盾的。
为什么筛选循环的第一层只循环至问题规模m的平方根+1
因为,对于一个数m,所有大于该数平方根的数的积已经大于该数了,再剔除下去只是多余。
为什么筛选循环的第二层只循环至MAX/i?
因为此时j*MAX/i就等于MAX,此时需要标记为错误的数已经到了问题的规模即MAX,没有必要在标记比MAX大的值不
是素数,此外用来标记i*j不是素数的数组只有MAX+1的容量,这样做是向不是自己申请的内存空间里写数据,是危
险的。
<span style="font-size:13px;">#include <iostream>#include <cstdlib>#include <cmath>using namespace std;const int MAX=1000;int main(){ int i=0,j=0,n=sqrt(MAX)+1; int a[MAX+1]={0}; for(i=2;i<=n;i++) //筛选循环 for(j=2;j<=MAX/i;j++) a[j*i]=1; for(i=2;i<=MAX;i++) if(a[i]==0) { cout.width(7); cout<<i<<" "; } system("pause"); return 0;}</span>
用a[i*j]来标记i*j不是素数,这一个相对来说比较容易想到
再来看看下一个(第二种,稍作了优化)
<span style="font-size:13px;">#include<stdio.h>#include<math.h>#define MAX_P 500int nList[MAX_P] = {0};void Calc() { int n,p,t,sq=(int)sqrt(MAX_P*2+1); for (n=3;n<=sq;n+=2) { if (nList[n>>1]) continue; for (t=n*n;t<=MAX_P<<1;t+=n<<1) //筛选循环 nList[t>>1] = 1; } printf("%5d", 2); for (n=t=1;t<MAX_P;++t) { if (nList[t]) continue; printf("%5d", (t<<1)+1); if (++n==10) { printf("\n"); n=0; } }}int main(void){ Calc(); getchar(); return 0;}</span>
这个程序的方法是通过排除3 5 7 9 11 … …中的素数n的奇数倍来排除素数的
用数组nList中的第[t/2]个元素的值(取1)来标记t不是素数。
1、为什么是奇数的倍数?
首先我们假设这个算法是正确的。由于素数除了2都是奇数,那么每次送入筛选循环的n值都是奇数,排除t时t的递
增表达式可写为
for(int i=0;i
<span style="font-size:13px;">#define MAX_N 1000int a[MAX_N+1];int p[MAX_N+1];int nCount=0;void Init(int n) //线性筛法,不过在小范围上(约n<1e7)不比上一个方法快{ for (int i=2;i<=n;i++) { if (a[i]==0) { p[++nCount]=i; } for (int j=1,k; (j<=nCount) && (k=i*p[j])<=n; j++) //筛选循环 { a[k] = 1 ; if (i%p[j] == 0) break; } }}#include <iostream>int main(void){ Init(MAX_N); for(int n=1; p[n]>1; ++n) { printf("%5d", p[n]); } return 0;}</span>
这一种可以说是对前种算法的直接变形
用a[k]=1来标记k不是素数
第一种是用筛选出来的正确的数(即素数)的倍数剔除合数
第二种是用2到n乘筛选出正确的数,即素数
如果你不以为然,我可以把for (n=3;n<=sq;n+=2)该为(n=3;n
- 三种素数筛选法详解 (转)
- 三种素数筛选法详解 (转)
- 三种素数筛选法详解 (转)
- 三种素数筛选法详解
- 三种素数筛选法详解
- 【转载】三种素数筛选法详解
- 三种素数筛选法
- 筛选法求素数(三种)
- 三种素数筛选方法
- 素数打表(三种筛选法)
- 筛选法求素数算法详解
- 筛选法求素数算法详解
- 筛选法求素数算法详解
- 筛选法求素数算法详解
- 根号法、埃氏法、欧拉筛选。三种方法求素数
- (转)筛选法求素数
- 筛选法求素数
- 筛选法求素数
- php中的mysqli_stmt_bind_param处理时间类型的方法
- C++ 内存分布
- HDU - 3631 Shortest Path(Floyd最短路)
- 软件设计说明书撰写概要
- bash常用
- 三种素数筛选法详解 (转)
- uva 194 - Triangle(几何)
- 4.[Python]使用logging记录日志
- 句柄类思想
- 网络安全系列之1:安全能力地图简介
- HDU 1754 I Hate It(线段树维护 区间最值)
- 【基础练习】【线性DP+离散化】codevs1105 过河题解
- 二维线段树
- ios文摘https和多线程