原文:http://blog.csdn.net/ltyqljhwcm/article/details/52835805

1.算法原理

埃拉托色尼素数筛法是有古希腊数学家发明的一种快速求解范围内所有的素数的算法
在我们讲解埃拉托色尼素数筛法之前,我们需要了解一下朴素的求素数的算法的工作原理

首先:

对于朴素的求素数的算法我们有过编程基础的人都会知道算法的原理很简单,首先从定义出发,一个数既然是素数那么就说明这个数除了1和本身以外不存在任何一个因子,所以朴素的算法就很直接的遍历一遍整个范围,我们对范围内的所有的数都进行判断,如果该数可以被整除说明不满足素数的条件,这样的话,对整个范围都进行一次比那里我们就可以判断一个数是不是素数
优化一下我们的朴素的求解思路,对于数来说,如果一个数的有因子的话(至少因子都是成对的),那么我们很显然会知道两个因子至少有一个会是小于等于sqrt(n)的,这一点是显然的,换个说法来看的话,如果一个数我们只要对他的sqrt(n)范围内进行遍历的话,只要在这个范围内是满足我们没有银子的条件,很显然这个数我们就可以认为是素数了,这么做可以减少我们的遍历的循环的次数
好了我们来总结一下,对于朴素的求素数的方法判断每个数是不是素数我们至少需要O(sqrt(n))即O(n)的时间复杂度,但是如果我们要是想要判断一整个范围内的所有的素数或者求范围内的素数的个数的话,我们朴素的方法就至少需要O(sqrt(n)*n)即O(n^2)的时间复杂度来做了,很显然当数据量非常大的时候这么做是有一些低效的
1 for(int i=2;i*i<N;i++)
2 {
3     if(d%i==0) break;
4 }

导入:

下面我们来解释一下著名的素数筛法,即埃拉托色尼素数筛法,本算法由著名的希腊数学家发明,算法的原理也是非常的简单,但是我们要求的不仅仅是初步的优化,之后我会讲解一系列的对埃拉托色尼算法的优化
首先在开始之前,我们需要了解到,埃拉托色尼素数筛法实际上是一种空间换时间的算法优化,对于判断单个数的素数性质来说,相对于朴素的算法没有优化,但是在求解范围素数问题的时候,埃拉托色尼素数筛法可以很快的打印一份范围内的素数表(该思路的时间复杂度我之后讲解)
首先,我们需要来了解一下
埃拉托色尼算法工作原理:
1.假定范围内的所有的数都是素数
2.我们从2开始,只要是2的倍数我们就认为该数不是素数,打标处理
3.直到判断到n为止我们就可以将所有的非素数打上标记,从而确定了所有的非素数
简单证明:反证法
假设应用算法流程之后我们得到了一组序列,如果该序列中存在一个非素数,说明该数必定存在因子d,那么对于在算法流程中我们对d的所有的倍数全部都打标处理了,所以说出现矛盾,埃拉托色尼素数筛法是正确的,可以得到正确的素数序列
附上代码直观一些:
 1 memset(prime,1,sizeof(prime));   //初始假设所有的数都是素数
 2
 3     prime[0]=prime[1]=0;   //初始确认0,1不是
 4     for(int i=2;i*i<N;i++)
 5     {
 6         if(prime[i])
 7         {
 8             for(int j=2;i*j<N;j++) prime[i*j]=0;
 9         }
10     }

对于朴素的埃拉托色尼素数筛法的时间复杂度我们来判断一下
1 n:扫描遍历次数
2 从2开始直到n我们进行倍数打标处理,每个循环到的数我们记为k
3 单次扫描的时间复杂度是O(n/k)
4 那么总的时间复杂度就是
5 T(n)=n/2+n/3+n/4+.....n/n(因为在算法的过程中我们是不断地筛掉的,所以说实际的时间复杂度是远远要比这个小的)
6 O(n)<T(n)
7 对于T(n)的求解,我们应用调和奇数的公式可以得到大致约为Ln(n)
8 所以说O(n)<O(n*logn)

当然你们可能会觉得算法比朴素的求素数的有点慢,但是注意我们的算法求解出来了整个范围的所有的素数,还算是相对来说比较高效的
优化1:
先陈述我们的优化,在这里我们还是没有必要遍历整个范围,我们只需要遍历到sqrt(n)就可以了
证明,我先说明这个证明确实废了我一些功夫
首先回顾埃拉托色尼素数筛法,我们进行的操作是打标处理,如果我们在sqrt(n)停止了打标处理,会错误吗
反证法:
假设我们操作之后还是存在非素数d没有被打标,那么该素数的sqrt(d)<sqrt(n)显然,那么就说明d还存在一个因子k<sqrt(d)<sqrt(n),但是按照埃拉托色尼算法,这个k的所有的倍数我们全部都打标了,所以说矛盾
证明成功
对于优化1来说我们明显降低了遍历次数
2016/10/29
优化1再优化,今天又得到了一种新的优化思路
因为在埃式筛法中我们都是从2倍开始一次的筛但是仔细注意我们会发现,实际上我们只用从i*i开始筛就好了,因为i*2,i*3....i*i-1都曾经被筛过了,我们只用从i*i开始就好,实际上在压力测试100000000(1亿)的时候我们会发现这样子我们可以优化一些时间,优化1的时间是4951,本次优化的时间压缩到了4321
还是很有用处的
附上代码:
1 for(int i=2;i<N;i++)
2     {
3         if(prime[i])
4         {
5             long long int j;
6             save[++count]=i;
7             for(j=pow(i,2);j<N;j+=i) prime[j]=0;
8         }
9     }

优化2:导入快速线性筛法
从上面的埃拉托色尼算法的流程来看,我们对于某些数其实进行了重复筛选的结果
比如12,我们分别在2,3,的时候重复了筛选,为了优化重复筛选的弊端,我们引入快速线性筛法
为了解释方便首先我们先引入代码段,之哦后我们对代码段进行解释
 1 memset(judge, 1, sizeof(judge));
 2     judge[1] = judge[0] = 0;
 3     for (int i=2;i<N;i++)
 4     {
 5         if (judge[i]) prime[++countp] = i;   //0
 6         for (int j=1;j<=countp&&i*prime[j]<N;j++)    //1
 7         {
 8             judge[i*prime[j]] = 0;
 9             if (!(i%prime[j])) break;   //2
10         }
11     }

线性素数筛法的解释:
对于埃拉托色你素数筛法,我们会发现有的素数我们会重复删除,比如12会被2,3判断两次,这样会大幅度的降低我们算法的时间复杂度,针对一些素数的基本性质和反证法,我来对快速线性筛法做一下简单的我证明和解释
首先:
1.任何一个合数都有唯一的素因子分解式(这也是我们唯一删除一次的应用原理)
对于任何一个合数,始终都在这个范围内
a.合数=素数*素数
b.合数=素数*合数

首先从代码的角度我来解释一下,快速先行筛法的思路如下:
1.从2开始
如果当前的i是素数的话对于1的内层循环我们始终是不会中途跳出的,也就是将当前i和i之前的所有的素数相乘得到的合数全部打标判负(对于合数=素数*素数的情况来看的话这样的删除效果是唯一的,不会重复删除,很容易可以判断出来)
如果当前的i是合数的话对于1的内层循环我们绝对会中途跳出(因为一个合数必定会表示成至少有一个素数参与的分解式)这样子的操作的目的是为了保证该情况下的删除是唯一的,不会重复删除
2.当整个数组遍历完之后,我们就会得到一个完整的素数表(这一点在下面我会用反证法证明)
证明:
1.证明该方案是不会漏筛合数的
反证法:
假设该方案我们会漏掉合数,假设合数是d
显然该合数d可以表示成:
1 d=d的最小素因子*w(该书可素可和,不考虑)
2 d的最小素因子必定小于等于w的最小素因子
3 (该结论应用反证法,如果d的最小素因子大于w最小素因子,那么对于d的最小素因子就不是一开始确定的值,所以说成立)
4 那么显然按照我们算法的流程来看的话在我们遍历到w的那个时候我们已经将d打标了,所以说和题设相矛盾
5 说明该算法对于筛素数是完全正确的,是不会漏筛的

2.证明该方案是不会重复删除合数的(也就是证明如果注释2处不跳出是会重复删除的)
假设合数k=p*w(p是素数,w是另一个k的因子)
如果p>w的最小素因子
对于k之后的素数h
我们就也要执行删除操作
因为h=pk*w(pk是p的下一个素数)=pw*ww(pw*ww的式子在ww遍历的时候会h会被打标,ww<w说明h之前被标记了,所以重复标记)
证明完成
综上我们可以总结出快速线性素数筛法在是正确的
因为快速线性素数筛法是不会出现对一个素数重复删除标记的情况,所以说对于埃拉托色尼素数筛法该速发的时间效率更高
 
为了验证算法的高效性,我对两种算法在压力测试100000000(1亿)的时候的耗时情况进行了大致的测试
实际显示快速先行筛法在大数据量的时候比埃拉托色你筛法要高效很多
 1 #include"iostream"
 2 #include"cstdio"
 3 #include"cstdlib"
 4 #include"time.h"
 5 #define N 100000000
 6
 7 using namespace std;
 8
 9 bool judge[N];
10
11 int main()
12 {
13     int count = 0;
14     double w = clock();
15     memset(judge, 1, sizeof(judge));
16     judge[1] = judge[0] = 0;
17     for (int i=2;i*i<N;i++)
18     {
19         if (judge[i])
20         {
21             for (int j = 2;i*j < N;j++) judge[i*j] = 0;
22         }
23     }
24     for (int i = 2;i < N;i++) if (judge[i]) count++;
25     printf("%lf\n%d\n", clock() - w,count);
26     return 0;
27 }*/

2.Last question

1.对于线性素数筛法还催你在什么好的优化
2.对于欧拉筛法和莫比乌斯筛法的学习算法原理

转载于:https://www.cnblogs.com/mhpp/p/8182841.html

埃拉托色尼素数筛法(转)相关推荐

  1. P1865 A % B Problem (素数筛法,前缀和)

    题目描述 区间质数个数 输入输出格式 输入格式: 一行两个整数 询问次数n,范围m 接下来n行,每行两个整数 l,r 表示区间 输出格式: 对于每次询问输出个数 t,如l或r∉[1,m]输出 Cros ...

  2. 斐波那契数列的3种求法及几种素数筛法

    递推法 #include<stdio.h> long long sum[40];//也可以不用开数组 int main() {int n;scanf("%d",& ...

  3. P1217 [USACO1.5]回文质数 Prime Palindromes(素数筛法/打表)

    P1217 [USACO1.5]回文质数 Prime Palindromes(素数筛法/打表) 一:埃氏筛(时间复杂度--nloglogn) 重点:一个数x是合数,则它的倍数也是合数 //用埃氏筛生成 ...

  4. 欧拉筛法原理C语言,素数筛法

    素数筛 自古以来,素数就是一个有众多人研究的东西,而素数筛也是这些研究成果中的一个 素数筛是用来快速生成一个素数表的东西,比起生成素数的幼稚算法及其优化的方法,素数筛的速度更快,但是也常常会出现很多奇 ...

  5. C语言:素数筛法与分解素因数

    一.素数筛法 素数筛法是关于求小于某个大数(正整数)的所有素数的算法,首先有理论:任何整数n≥2都可以分解成若干质数的乘积,即n=p1p2···pr. 用筛法求素数的基本思想是:把从1开始的.某一范围 ...

  6. 线性筛法求素数c语言,[算法]素数筛法(埃氏筛法线性筛法)

    一.素数筛的定义 给定一个整数n,求出[1,n]之间的所有质数(素数),这样的问题为素数筛(素数的筛选问题). 二.埃氏筛法(Eratosthenes筛法) 埃氏筛法又叫做Eratosthenes筛法 ...

  7. 素数筛法(传统普通、朴素筛法、埃式筛法、欧拉筛法(线性筛))

    素数筛法(普通.朴素筛法.埃式筛法.欧拉筛法) 1.题目 2.分析 3.代码 传统普通 朴素筛法 朴素筛法(6.14) 埃式筛法 埃式筛法(6.14) 欧拉筛法(线性筛) 欧拉筛法(线性筛 6.14) ...

  8. 素数判定(素数筛法)(欧拉)

    这里主要说一下 素数筛法,该方法可以快速的选取出1~N数字中的所有素数.时间复杂度 远小于O(N*sqrt(N)) 方法为:从2开始,往后所有素数的倍数都不是素数.最后剩下的数都是素数. 再说说欧拉公 ...

  9. [原]素数筛法【Sieve Of Eratosthenes + Sieve Of Euler】

    拖了有段时间,今天来总结下两个常用的素数筛法: 1.sieve of Eratosthenes[埃氏筛法] 这是最简单朴素的素数筛法了,根据wikipedia,时间复杂度为 ,空间复杂度为O(n). ...

最新文章

  1. openstack-mitaka之Telemetry服务(controller安装部署)
  2. sqlite3.OperationalError: database is locked
  3. ES6--基础语法(一)
  4. [ARM-assembly]-全局变量/静态全局变量/初始化/未初始化变量的存放位置分析
  5. SpringCloud微服务架构,Config 分布式配置中心,Bus 消息总线, Stream 消息驱动,Sleuth+Zipkin 链路追踪
  6. 中img拉伸_8个拉伸动作,帮你调动全身肌肉,提高柔韧性,缓解疲劳放松心情...
  7. Python 模块安装失败
  8. 组合数取模模板(2)
  9. 用CSS hack技术解决浏览器兼容性问题
  10. [Zer0pts2020]ROR1
  11. 使用Sbo用户自定义业务对象
  12. 计算机视觉 OpenCV【六:应用之颜色检测】
  13. Ural_1671. Anansi's Cobweb(并查集)
  14. android直接连接本地数据库文件,Android 直接连MySQL数据库
  15. https域名安全证书怎么配置
  16. KBEngine warring项目源码阅读(二) 登录和baseapp的负载均衡
  17. 【2022.1】触控板可以点击但无法滑动ThinkPad一个驱动问题
  18. 反爬虫原理与绕过实战
  19. 中学计算机课小课题,小学信息技术课堂有效教学的探索课题
  20. mysql set password_MySQL SET PASSWORD语法示例

热门文章

  1. VMware vSphere学习整理
  2. bzoj1095: [ZJOI2007]Hide 捉迷藏 动态点分治学习
  3. vs中调试中的命令行参数
  4. 只要暴风骤雨才能使人迅速地成长
  5. JS两种声明函数的方法以及调用顺序
  6. android之音乐播放和音效播放
  7. 双绞线网线的连接方式
  8. 嵌入式SQL程序的VC+SQL server 2000实现的环境配置
  9. 为什么Java需要lambda 表达式?
  10. MySQL集群节点宕机,数据库脑裂!如何排障?