最简单的筛素数法方法就是从2开始,将所以2的倍数去掉,然后从3开始,将3的倍数去掉。根据这样很容易写出代码,下面代码就是是筛素数法得到100以内的素数并保存到primes[]数组中。

[cpp] view plaincopy
  1. //by MoreWindows( http://blog.csdn.net/MoreWindows )
  2. const int MAXN = 100;
  3. bool flag[MAXN];
  4. int primes[MAXN / 3], pi;
  5. void GetPrime_1()
  6. {
  7. int i, j;
  8. pi = 0;
  9. memset(flag, false, sizeof(flag));
  10. for (i = 2; i < MAXN; i++)
  11. if (!flag[i])
  12. {
  13. primes[pi++] = i;
  14. for (j = i; j < MAXN; j += i)
  15. flag[j] = true;
  16. }
  17. }

可以看出这种会有很多重复访问,如在访问flag[2]和flag[5]时会各访问flag[10]一次。因此最好想方法来减少这种重复访问,让flag[]数组的每个元素只被访问一次。可以这样考虑——简单的筛素数法是利用一个素数的倍数必须不是素数,同样任何一个数与其它所有素数的乘积必然也不是素数(这是因为每个合数必有一个最小素因子)。

为了试验这种想法,先用2到10之间的数来验证下。

2,3,4,5,6,7,8,9,10      初始时所以flag都是无标记的。

第一步 访问2,flag[2]无标记所以将2加入素数表中,然后将2与素数表中的所有数相乘得到的数必定不是素数,2*2=4因此标记flag[4]。

2,3,4,5,6,7,8,9,10

第二步 访问3,flag[3]无标记所以将3加入素数表中,将3与素数表中的所有数相乘得到的数必定不是素数,3*2=6,3*3=9因此标记flag[6]和flag[9]。

2,3,4,5,6,7,8,9,10

第三步 访问4,flag[4]有标记所以4不加入素数表中,将4与素数表中的所有数相乘得到的数必定不是素数, 4*2=8,4*3=12因此标记flag[8]。

2,3,4,5,6,7,89,10

第四步 访问5,flag[5]无标记所以将5加入素数表中,将5与素数表中的所有数相乘得到的数必定不是素数,5*2=10,5*3=15因此标记flag[10]。

2,3,4,5,6,7,8910

第五步 访问6,flag[6]有标记所以6不加入素数表中,将6与素数表中的所有数相乘得到的数必定不是素数, 6*2=12,6*3=18,6*5=30。

2,3,4,5,6,7,8910

后面几步类似,代码不难写出:

[cpp] view plaincopy
  1. //by MoreWindows( http://blog.csdn.net/MoreWindows )
  2. const int MAXN = 100;
  3. bool flag[MAXN];
  4. int primes[MAXN / 3], pi;
  5. void GetPrime_2()
  6. {
  7. int i, j;
  8. pi = 0;
  9. memset(flag, false, sizeof(flag));
  10. for (i = 2; i < MAXN; i++)
  11. {
  12. if (!flag[i])
  13. primes[pi++] = i;
  14. for (j = 0; (j < pi)  && (i * primes[j] < MAXN); j++)
  15. flag[i * primes[j]] = true;
  16. }
  17. }

这份代码对不对了?仔细回顾下分析过程,可以发现有些数据还是被访问多次了,这当然不是我们希望的结果,我们的要求是让每个合数仅被它的最小素因子筛去一次。比如12,它的最小素因子是2,所以就只应该被在计算6*2时去访问,而且不应该在计算4*3时去访问,同理18也只应该被在计算9*2时去访问,而且不应该在计算6*3时去访问。

找到原因后,再来思考如何解决。6*3不行而9*2可以了,是因为6是2的倍数,所以在计算6*2之后就不能再将6与比2大的素数相乘,这些相乘的结果必定会导致重复计算。因此对于任何数来说,如果它如果是该素数的倍数那么它就不能再与素数表中该素数之后的素数相乘了,如9是3的倍数,所以在9*3之后就不能再去用计算9*5了。因此在代码中再增加一行判断语句:

[cpp] view plaincopy
  1. //by MoreWindows( http://blog.csdn.net/MoreWindows )
  2. const int MAXN = 100;
  3. bool flag[MAXN];
  4. int primes[MAXN / 3], pi;
  5. void GetPrime_2()
  6. {
  7. int i, j;
  8. pi = 0;
  9. memset(flag, false, sizeof(flag));
  10. for (i = 2; i < MAXN; i++)
  11. {
  12. if (!flag[i])
  13. primes[pi++] = i;
  14. for (j = 0; (j < pi)  && (i * primes[j] < MAXN); j++)
  15. {
  16. flag[i * primes[j]] = true;
  17. if (i % primes[j] == 0) //这句保证每个非素数只被筛去一次
  18. break;
  19. }
  20. }
  21. }

想知道这二种筛素数法方法的区别吗?现在对求2到1亿之间的素数进行测试,看看区别到底会有多大,测试代码如下:

[cpp] view plaincopy
  1. // 普通的筛素数方法与改进之后的效率对比
  2. // by MoreWindows( http://blog.csdn.net/MoreWindows )
  3. #include <stdio.h>
  4. #include <memory.h>
  5. #include <time.h>
  6. #include <math.h>
  7. const int MAXN = 100000000;
  8. bool flag[MAXN];
  9. int primes[MAXN / 3], pi;
  10. // 利用对每个素数的倍数必定不是素数来筛选
  11. void GetPrime_1()
  12. {
  13. int i, j;
  14. pi = 0;
  15. memset(flag, false, sizeof(flag));
  16. for (i = 2; i < MAXN; i++)
  17. if (!flag[i])
  18. {
  19. primes[pi++] = i;
  20. for (j = i; j < MAXN; j += i)
  21. flag[j] = true;
  22. }
  23. }
  24. // 利用了每个合数必有一个最小素因子来筛选
  25. void GetPrime_2()
  26. {
  27. int i, j;
  28. pi = 0;
  29. memset(flag, false, sizeof(flag));
  30. for (i = 2; i < MAXN; i++)
  31. {
  32. if (!flag[i])
  33. primes[pi++] = i;
  34. for (j = 0; (j < pi)  && (i * primes[j] < MAXN); j++)
  35. {
  36. flag[i * primes[j]] = true;
  37. if (i % primes[j] == 0)
  38. break;
  39. }
  40. }
  41. }
  42. int main()
  43. {
  44. printf(" 在%d的数据量下普通的筛素数方法与改进之后的效率对比\n", MAXN);
  45. printf("  by MoreWindows( http://blog.csdn.net/MoreWindows ) -- --\n\n");
  46. clock_t clockBegin, clockEnd;
  47. clockBegin = clock();
  48. GetPrime_1();
  49. clockEnd = clock();
  50. printf("普通的筛素数方法\t%d毫秒\n", clockEnd - clockBegin);
  51. clockBegin = clock();
  52. GetPrime_2();
  53. clockEnd = clock();
  54. printf("改进的筛素数方法\t%d毫秒\n", clockEnd - clockBegin);
  55. return 0;
  56. }

测试结果如图所示:

可以看出,效率有4倍之差。改进还是比较可观。有兴趣的同学可以参考下一篇《位操作基础篇之位操作全面总结》所讲到的空间压缩技巧来将改进后的筛素数法方进行空间压缩。

文章最后作下小小总结:

1.普通的筛素数的原理是一个素数的倍数必须不是素数。

2.改进的筛素数的原理是每个合数必有一个最小素因子,根据每个最小素因子去访问合数就能防止合数被重复访问。

另外,筛素数法还有很多种改进手段,在数学论坛上可以去研读一下,本文就不再深究了。

转载请标明出处,原文地址:http://blog.csdn.net/morewindows/article/details/7347459

如果觉得本文对您有帮助,请点击‘顶’支持一下,您的支持是我写作最大的动力,谢谢。

转载于:https://www.cnblogs.com/wmxl/p/4662712.html

改进的筛素数法 2014-11-29 16:16 29人阅读 评论(0) 收藏...相关推荐

  1. TensorFlow损失函数(loss function) 2017-08-14 11:32 125人阅读 评论(0) 收藏 举报 分类: 深度学习及TensorFlow实现(10) 版权声明:

    TensorFlow损失函数(loss function) 2017-08-14 11:32 125人阅读 评论(0) 收藏 举报  分类: 深度学习及TensorFlow实现(10)  版权声明:本 ...

  2. 2014/12/05 随笔 2014-12-05 12:50 26人阅读 评论(0) 收藏...

    有一段时间没写博客了..发现博客出现了两篇空的博文..不知道是怎么回事..估计是CSDN眼子了 - -, 最近因为忙于辞职的事情,还是比较纠结的... 嗯 这篇文章就分享一下在写代码的时候EF闹眼子的 ...

  3. C++ 代码模拟登录淘宝、天猫、支付宝等电商网站的实现 分类: C/C++ 随笔杂文 2015-01-26 11:17 3787人阅读 评论(9) 收藏 举报 有关C++ 代码模拟登录淘宝、天猫、支

    C++ 代码模拟登录淘宝.天猫.支付宝等电商网站的实现 http://blog.csdn.net/rrrfff/article/details/43149993 有关C++ 代码模拟登录淘宝.天猫.支 ...

  4. 凯立德2014秋季机车版C1204-C7K05-3323J0L懒人包 (5.0版)

    轉自:http://www.chenmoguoke.com/rjjp/gps/632.html#respond 凯立德2014秋季机车版C1204-C7K05-3323J0L懒人包 2014年11月0 ...

  5. HDU 5750 快速筛素数法打表

    题目大意:x能整除n,x就是n的positive proper divisor,但n本身不算,给你两个数n和d,找出所有小于n的数中,最大positive proper divisor是d个数,T组测 ...

  6. 构建之法1、2、16章观后有感

    构建之法1.2.16章观后有感 构建之法1.2.16章观后有感 第一章 概论 问题:何为BUG?要以怎样的态度对待BUG? 教材内容:P16.17 思考:说到BUG,大家的第一反应是漏洞.错误和失败品 ...

  7. Java黑皮书课后题第6章:**6.29(双素数)双素数是指一对差值为2的素数。例如,3和5就是一对双素数,5和7是一对双素数,而11和13也是一对双素数。编写程序,找出小于1000的所有双素数

    6.29(双素数)双素数是指一对差值为2的素数.例如,3和5就是一对双素数,5和7是一对双素数,而11和13也是一对双素数.编写程序,找出小于1000的所有双素数 题目 题目描述 破题 代码 运行示例 ...

  8. Composite Coloring(思维 数论(筛素数 分解质因数))

    (29条消息) CodeForces - 1332B Composite Coloring(数论+构造)_Frozen_Guardian的博客-CSDN博客 (29条消息) codeforces 13 ...

  9. 2404 Super Prime(欧拉筛素数)

    2404 Super Prime(欧拉筛素数) Problem Description We all know, prime is a kind of special number which has ...

最新文章

  1. 金九银十铁12,看完弄懂,工资少说加 5K
  2. 适用于WinForm的一个定时器类
  3. 【LoadRunner】安装LoadRunner时提示缺少vc2005_sp1_with_atl_fix_redist解决方案
  4. Java课堂测试01及感想
  5. ado mfc mysql_MFC 中用ADO访问数据库
  6. SOT23-6封装随机数发生芯片,串行接口
  7. python入门教程(非常详细)-Python超详细入门教程(上)
  8. java https请求 证书_java发https请求,证书配置
  9. 20165202 实验一 Java开发环境的熟悉
  10. 2018年湘潭大学程序设计竞赛 - 题解
  11. WiFi语音智能家居控制系统(一)
  12. 使用计算机时正确的开关机顺序,电脑开关机的正确操作
  13. 第一次初学游泳+自我总结+小窍门
  14. Eclipse 远程开发插件 RSE 及远程登录
  15. Excel无法跨表筛选,也不能多列筛选,要如何突破限制呢?本教材有方法
  16. 剑指 Offer 19. 正则表达式匹配 regex_match() regex()
  17. Pytorch实现多层lstm
  18. 芯盾时代完成3亿元C轮融资,宽带资本领投
  19. execl筛选去重_Excel去除重复项的三种常用技巧
  20. 怎样训练左右手协调_钢琴的左右手应该怎么协调

热门文章

  1. html HTML 文本格式化
  2. 查询表达式和LINQ to Objects
  3. Google的wiki-map也上线了
  4. SQL Server IDENDITY 的用法
  5. Java虚拟机专题之垃圾回收(读书笔记)
  6. HBase之MemStore flush流程
  7. curl http_code 状态码 意义及信息
  8. 11.FreeRTOS学习笔记-内存管理
  9. 1009. clion调试段错误
  10. 05.Qt设置背景图片