筛素数法小结

简介:

筛选素数方法小结:

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

复制代码
复制代码
 1 const int MAXN = 100;
 2 bool flag[MAXN];
 3 int primes[MAXN / 3], pi;
 4 void GetPrime_1()
 5 {
 6     int i, j;
 7     pi = 0;
 8     memset(flag, false, sizeof(flag));
 9     for (i = 2; i < MAXN; i++)
10         if (!flag[i])
11         {
12             primes[pi++] = i;
13             for (j = i; j < MAXN; j += i)  //剔除待考察数据j的倍数,并置其flag位为true
14                 flag[j] = true;
15         }
16 }
复制代码
复制代码

  可以看出这种会有很多重复访问,如在访问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,8,9,10

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

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

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

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

    后面几步类似,具体代码如下:

复制代码
复制代码
 1 const int MAXN = 100;
 2 bool flag[MAXN];
 3 int primes[MAXN / 3], pi;
 4 void GetPrime_2()
 5 {
 6     int i, j;
 7     pi = 0;
 8     memset(flag, false, sizeof(flag));
 9     for (i = 2; i < MAXN; i++)
10     {
11         if (!flag[i])
12             primes[pi++] = i;  //flag未标记为true,将其加入到素数表中
13         for (j = 0; (j < pi)  && (i * primes[j] < MAXN); j++)  //依次剔除待考察数据与素数表中数据的乘积,并置其flag位为true
14             flag[i * primes[j]] = true;
15     }
16 }
复制代码
复制代码

  这份代码对不对呢?仔细回顾下分析过程,可以发现有些数据还是被访问了多次,这当然不是我们希望的结果,我们的要求是让每个合数仅被它的最小素因子筛去一次。比如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了。因此在代码中再增加一行判断语句:

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

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

复制代码
复制代码
 1 /*
 2 *描述:筛素数法(倍数剔除、最小素因子筛选)对比
 3 *分析:倍数剔除:一个素数的倍数必须不是素数,即从2开始,将所以2的倍数去掉,然后从3开始,将3的倍数去掉,依次进行下去即可
 4 *       最小素因子筛选:简单的筛素数法(倍数剔除)是利用一个素数的倍数必须不是素数,同样任何一个数与其它所有素数的乘积必然也不是素数(这是因为每个合数必有一个最小素因子)。
 5                        要求是让每个合数仅被它的最小素因子筛去一次;即如果它是该素数的倍数那么它就不能再与素数表中该素数之后的素数相乘了。
 6 *
 7 *
 8 */
 9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <memory.h>
12 #include <time.h>
13 #include <math.h>
14 const int MAXN = 100000000;
15 bool flag[MAXN];
16 int primes[MAXN / 3], pi;
17 // 利用对每个素数的倍数必定不是素数来筛选
18 void GetPrime_1()
19 {
20     int i, j;
21     pi = 0;
22     memset(flag, false, sizeof(flag));
23     for (i = 2; i < MAXN; i++)
24         if (!flag[i])
25         {
26             primes[pi++] = i;
27             for (j = i; j < MAXN; j += i)
28                 flag[j] = true;
29         }
30 }
31 // 利用了每个合数必有一个最小素因子来筛选
32 void GetPrime_2()
33 {
34     int i, j;
35     pi = 0;
36     memset(flag, false, sizeof(flag));
37     for (i = 2; i < MAXN; i++)
38     {
39         if (!flag[i])
40             primes[pi++] = i;
41         for (j = 0; (j < pi)  && (i * primes[j] < MAXN); j++)
42         {
43             flag[i * primes[j]] = true;
44             if (i % primes[j] == 0)
45                 break;
46         }
47     }
48 }
49 int main()
50 {
51     printf(" 在%d的数据量下普通的筛素数方法与改进之后的效率对比\n", MAXN);
52     clock_t clockBegin, clockEnd;
53     
54     clockBegin = clock();
55     GetPrime_1();
56     clockEnd = clock();
57     printf("普通的筛素数方法\t%d毫秒\n", clockEnd - clockBegin);
58     
59     clockBegin = clock();
60     GetPrime_2();
61     clockEnd = clock();
62     printf("改进的筛素数方法\t%d毫秒\n", clockEnd - clockBegin);
63     system("pause");
64     return 0;
65 }


本文转自我爱物联网博客园博客,原文链接:http://www.cnblogs.com/yydcdut/p/3876195.html,如需转载请自行联系原作者
相关文章
|
7月前
|
安全 网络安全 数据安全/隐私保护
Jsch连接服务器失败解决办法其他工具可以连接成功但是Jsch不行解决办法
Jsch连接服务器失败解决办法其他工具可以连接成功但是Jsch不行解决办法
312 0
|
5月前
|
域名解析 监控 CDN
搭建SRS直播服务器
搭建SRS直播服务器涉及下载安装包,解压后运行`./INSTALL`安装。配置`srs.conf`文件调整服务器参数,如端口和带宽。使用OBS等工具推流,VLC等播放器或浏览器拉流。配置域名解析和CDN以优化访问。监控服务器状态并进行调优确保稳定性。参照官方文档和社区资源可获取详细指导。祝搭建成功!
289 8
|
4月前
|
JavaScript
NGROK——Invalid Host header
NGROK——Invalid Host header
63 0
|
域名解析 安全 网络协议
阿里云SSL证书免费版申请教程,可申请20张DV单域名证书
SSL证书能够为网站和移动应用(APP)及小程序提供数据HTTPS加密协议访问,保障数据的安全。阿里云提供一次性申请20张免费证书额度的服务,满足您的业务需求。
1637 0
阿里云SSL证书免费版申请教程,可申请20张DV单域名证书
|
存储 运维 监控
我对 SRE 的理解
产品/基础技术研发 和 SRE 这两类角色是相互协作、相互服务的关系,拥有共同的目标:满足业务需求,更好服务业务。
3500 9
我对 SRE 的理解
|
SQL 存储 数据库
12.【clickhouse】ClickHouse从入门到放弃-环境搭建
【clickhouse】ClickHouse从入门到放弃-环境搭建
12.【clickhouse】ClickHouse从入门到放弃-环境搭建
|
数据可视化 安全 Linux
Linux目录和文件管理:mkdir、touch、cp、mv、rm
1 创建 文件名最长255个字节 包括路径在内文件名称最长4095个字节 除了斜杠和NULL,所有字符都有效.但使用特殊字符的目录名和文件不推荐使用,有些字符需要用引 号来引用
356 0
|
SQL HIVE
Hive SQL语句的正确执行顺序
关于 sql 语句的执行顺序网上有很多资料,但是大多都没进行验证,并且很多都有点小错误,尤其是对于 select 和 group by 执行的先后顺序,有说 select 先执行,有说 group by 先执行,到底它俩谁先执行呢?
1402 0
Hive SQL语句的正确执行顺序
|
XML Java 测试技术
Mybatis-Plus字段策略FieldStrategy详解
Mybatis-Plus字段策略FieldStrategy详解
1973 0
Mybatis-Plus字段策略FieldStrategy详解