作为计算机小白,今天碰到筛选法判断素数,刚开始有点不理解,特此记录一下。
关于素数的算法是信息学竞赛和程序设计竞赛中常考的数论知识,在这里我跟大家讲一下寻找一定范围内素数的几个算法。看了以后相信对大家一定有帮助。
正如大家都知道的那样,一个数 n 如果是合数,那么它的所有的因子不超过sqrt(n)–n的开方,那么我们可以用这个性质用最直观的方法来求出小于等于n的所有的素数。
普通方法
//最普通的方法:
#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)
printf("%d ",i);
return 0;
}
筛选法
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int>prime(10000,1);//判断10000以内素数,初值全设为1
for(int i=2;i<100;i++)//第一个素数是2,i的范围只要取sqrt(n)即可
{
if(prime[i])//prime[i]为1,代表这个数还没作为过因子
{
for(int j=i+i;j<10000;j+=i)//j+=i理解为j=i*(i+1),j=i*(i+2)....
{
v[j]=0;//有除1和本身之外的因子,不是素数
}
}
}
}
装了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 (每个单元代表的数是2i+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 2i+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](就是223+3=49)开始筛。
于是外围循环为i时,内存循环的筛法是从 i+(2i+3)(i+1)即i(2*i+6)+3开始筛的。
这个优化也对算法复杂度的降低起到了很大的作用。
1.高斯猜测,n以内的素数个数大约与n/ln(n)相当,或者说,当n很大时,两者数量级相同。这就是著名的素数定理。
2.十七世纪费马猜测,2的2n次方+1,n=0,1,2…时是素数,这样的数叫费马素数,可惜当n=5时,232+1就不是素数,
至今也没有找到第六个费马素数。
3.18世纪发现的最大素数是231-1,19世纪发现的最大素数是2127-1,20世纪末人类已知的最大素数是2^859433-1,用十进制表示,这是一个258715位的数字。
4.孪生素数猜想:差为2的素数有无穷多对。目前知道的最大的孪生素数是1159142985×22304-1和1159142985×22304+1。
5. 歌德巴赫猜想:大于2的所有偶数均是两个素数的和,大于5的所有奇数均是三个素数之和。其中第二个猜想是第一个的自然推论,因此歌德巴赫猜想又被称为1+ 1问题。我国数学家陈景润证明了1+2,即所有大于2的偶数都是一个素数和只有两个素数因数的合数的和。国际上称为陈氏定理。