首页 / 算法 / 素数推断算法(高效率)
素数推断算法(高效率)
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了素数推断算法(高效率),小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含4734字,纯文字阅读大概需要7分钟。
内容图文
![素数推断算法(高效率)](/upload/InfoBanner/zyjiaocheng/1295/d270cdd83ee0412283ae71581b61eec2.jpg)
chuanbindeng 的 素数推断算法
关于素数的算法是信息学竞赛和程序设计竞赛中常考的数论知识,在这里我跟大家讲一下寻找一定范围内素数的几个算法。看了以后相信
对大家一定有帮助。
正如大家都知道的那样,一个数 n 假设是合数,那么它的全部的因子不超过 sqrt(n)--n 的开方 , 那么我们能够用这个性质用最直观的方法
来求出小于等于 n 的全部的素数。
num = 0;
for(i=2; i<=n; i++)
{ for(j=2; j<=sqrt(i); j++)
if( j%i==0 ) break;
if( j>sqrt(i) ) prime[num++] = i; // 这个 prime[] 是 int 型,跟以下讲的不同。
}
这就是最一般的求解 n 以内素数的算法。复杂度是 o(n*sqrt(n)) ,假设 n 非常小的话,这样的算法(事实上这是不是算法我都怀疑,没有水平。当然没
接触过程序竞赛之前我也仅仅会这一种求 n 以内素数的方法。 -_-~ )不会耗时非常多 .
可是当 n 非常大的时候,比方 n=10000000 时, n*sqrt(n)>30000000000, 数量级相当大。在一般的机子它不是一秒钟跑不出结果,它是好几分钟都跑不
出结果,这可不是我瞎掰的,想锻炼耐心的同学最好还是试一试 ~ 。。。。
在程序设计竞赛中就必需要设计出一种更好的算法要求能在几秒钟甚至一秒钟之内找出 n 以内的全部素数。于是就有了素数筛法。
(我表达得不清楚的话不要骂我,见到我的时候扁我一顿我不说一句话。。。)
素数筛法是这种:
1. 开一个大的 bool 型数组 prime[] ,大小就是 n+1 就能够了 . 先把全部的下标为奇数的标为 true, 下标为偶数的标为 false.
2. 然后:
for( i=3; i<=sqrt(n); i+=2 )
{ if(prime[i])
for( j=i+i; j<=n; j+=i ) prime[j]=false;
}
3. 最后输出 bool 数组中的值为 true 的单元的下标,就是所求的 n 以内的素数了。
原理非常easy,就是当 i 是质 ( 素 ) 数的时候, i 的全部的倍数必定是合数。假设 i 已经被推断不是质数了,那么再找到 i 后面的质数来把这个质
数的倍数筛掉。
一个简单的筛素数的过程: n=30 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
第 1 步过后 2 4 ... 28 30 这 15 个单元被标成 false, 其余为 true 。
第 2 步開始:
i=3; 因为 prime[3]=true, 把 prime[6], [9], [12], [15], [18], [21], [24], [27], [30] 标为 false.
i=4; 因为 prime[4]=false, 不在继续筛法步骤。
i=5; 因为 prime[5]=true, 把 prime[10],[15],[20],[25],[30] 标为 false.
i=6>sqrt(30) 算法结束。
第 3 步把 prime[] 值为 true 的下标输出来:
for(i=2; i<=30; i++)
if(prime[i]) printf("%d ",i);
结果是 2 3 5 7 11 13 17 19 23 29
这就是最简单的素数筛选法,对于前面提到的 10000000 内的素数,用这个筛选法能够大大的减少时间复杂度。把一个仅仅见黑屏的算法
优化到立竿见影,一下就得到结果。关于这个算法的时间复杂度,我不会描写叙述,没看到过相似的记载。仅仅知道算法书上如是说:前几年比
较好的算法的复杂度为 o(n), 空间复杂度为 o(n^(1/2)/logn). 另外还有时间复杂度为 o(n/logn), 但空间复杂度为 O(n/(lognloglogn)) 的算法。
我水平有限啦,自己分析不来。最有说服力的就是自己上机试一试。以下给出这两个算法的程序:
// 最普通的方法:
#include<stdio.h>
#include<math.h>
#define N 10000001
int prime[N];
int main()
{
int i, j, num = 0;
for(i=2; i<N; i++)
{ for(j=2; j<=sqrt(i); j++)
if( j%i==0 ) break;
if( j>sqrt(i) ) prime[num++] = i;
}
for(i=2; i<100; i++) // 因为输出将占用太多 io 时间,所以仅仅输出 2-100 内的素数。能够把 100 改为 N
if( prime[i] )printf("%d ",i);
return 0;
}
// 用了筛法的方法:
#include<stdio.h>
#include<math.h>
#define N 10000001
bool prime[N];
int main()
{
int i, j;
for(i=2; i<N; i++)
if(i%2) prime[i]=true;
else prime[i]=false;
for(i=3; i<=sqrt(N); i++)
{ if(prime[i])
for(j=i+i; j<N; j+=i) prime[i]=false;
}
for(i=2; i<100; i++)// 因为输出将占用太多 io 时间,所以仅仅输出 2-100 内的素数。能够把 100 改为 N
if( prime[i] )printf("%d ",i);
return 0;
}
装了 vc 的同学上机跑一下这两个程序试一试。这个区别,绝对是天上地下。前面那个程序绝对是 n 分钟黑屏的说。
另外,对于这种筛法,还能够进一步优化,就是 bool 型数组里面仅仅存奇数不存偶数。如定义 prime[N], 则 0 表示
3 , 1 表示 5 , 2 表示 7 , 3 表示 9... 。假设 prime[0] 为 true, 则表示 3 时素数。 prime[3] 为 false 意味着 9 是合数。
这种优化不是简单的降低了一半的循环时间,比方依照原始的筛法,数组的下标就相应数。则在计算 30 以内素
数的时候 3 个步骤加起来走了 15 个单位时间。可是用这种优化则是这样:
则因为仅仅存 3 5 7 9 11 13 15 17 19 21 23 25 27 29 ,仅仅须要 14 个单元
第 1 步 把 14 个单元赋为 true ( 每一个单元代表的数是 2*i+3, 如第 0 单元代表 3 ,第 1 单元代表 5...)
第 2 步開始:
i=0; 因为 prime[0]=true, 把 [3], [6], [9], [12] 标为 false.
i=1; 因为 prime[1]=true, 把 [6], [11] 标为 false
i=2 2*i+3>sqrt(30) 算法结束。
这样优化以后总共仅仅走 6 个单位时间。
当 n 相当大以后这种优化效果就更加明显,效率绝对不不过翻倍。
出了这种优化以外,另外在每一次用当前已得出的素数筛选后面的数的时候能够一步跳到已经被判定不是素数的
数后面,这样就降低了大量的反复计算。(比方我们看到的, i=0 与 i=1 时都标了 [6], 这个就是反复的计算。)
我们能够发现一个规律,那就是 3 (即 i=0 )是从下标为 [3] 的開始筛的, 5 (即 i=1 )是从下标为 [11] 開始筛的(由于 [6]
已经被 3 筛过了)。然后假设 n 非常大的话,继续筛。 7 ( i=2 )本来应该从下标为 [9] 開始筛,可是因为 [9] 被筛过了,而
[16] 也已经被 5 ( i=1 )筛过了。于是 7 ( i=2 )从 [23] (就是 2*23+3=49 )開始筛。
于是外围循环为 i 时,内存循环的筛法是从 i+(2*i+3)*(i+1) 即 i*(2*i+6)+3 開始筛的。
这个优化也对算法复杂度的减少起到了非常大的作用。
相比于一般的筛法,添?这两个优化后的筛法要高效非常多。高兴去的同学能够试着自己编敲代码看一看效率。我这里
有程序,须要的能够向我要。不懂得也能够问我。
上面的素数筛法是全部程序设计竞赛队员都必须掌握的,而后面加了两个优化的筛法是效率非常高的算法,是湖南大学
huicpc39 同学设计的(可能是学来的,也可能是自创的。相当强悍)。在数量级更大的情况下就能够发现一般筛法和
优化后的筛法的明显差别。
另外,台湾的 ACMTino 同学也给我介绍了他的算法: a 是素数,则下一个起点是 a*a, 把后面的全部的 a*a+2*i*a 筛掉。
这上面的全部的素数筛选的算法都能够再进一步化为二次筛选法,就是欲求 n 以内的素数,就先把 sqrt(n) 内的素数求
出来,用已经求得的素数来筛出后面的合数。
我把一般的筛选法的过程具体的叙述了一遍,应该都懂了吧?后面的优化过程及不同的方法,能看懂最好。不是非常难的。
相关知识:
最大公约数仅仅有 1 和它本身的数叫做质数(素数)——这个应该知道吧? -_-b
至今为止,没有不论什么人发现素数的分布规律,也没有人能用一个公式计算出全部的素数。关于素数的非常多的有趣的性质或者科学家的努力
我不在这里多说,大家有兴趣的话能够到百度或 google 搜一下。我在以下列出了一个网址,上面仅仅有个大概。很多其它的知识须要大家一点一点
地动手收集。
http://www.scitom.com.cn/discovery/universe/home01.html
1. 高斯推測, n 以内的素数个数大约与 n/ln(n) 相当,或者说,当 n 非常大时,两者数量级同样。这就是著名的素数定理。
2. 十七世纪费马推測, 2 的 2^n 次方 +1 , n=0 , 1 , 2 …时是素数,这种数叫费马素数,可惜当 n=5 时, 2^32+1 就不是素数,
至今也没有找到第六个费马素数。
3.18 世纪发现的最大素数是 2^31-1 , 19 世纪发现的最大素数是 2^127-1 , 20 世纪末人类已知的最大素数是 2^859433-1 ,用十进制表示,这是一个 258715 位的数字。
4. 孪生素数猜想:差为 2 的素数有无穷多对。眼下知道的最大的孪生素数是 1159142985 × 2^2304 - 1 和 1159142985 × 2^2304 + 1 。
5. 歌德巴赫猜想:大于 2 的全部偶数均是两个素数的和,大于 5 的全部奇数均是三个素数之和。当中第二个猜想是第一个的自然推论,因此歌德巴赫猜想又被称为 1+1 问题。我国数学家陈景润证明了 1+2 ,即全部大于 2 的偶数都是一个素数和仅仅有两个素数因数的合数的和。国际上称为陈氏定理。
原文:http://www.cnblogs.com/hrhguanli/p/4022971.html
内容总结
以上是互联网集市为您收集整理的素数推断算法(高效率)全部内容,希望文章能够帮你解决素数推断算法(高效率)所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。