求素数

转载 2015年07月06日 22:05:14
 素数筛法是这样的: 
    1.开一个大的bool型数组prime[],大小就是n+1就可以了.先把所有的下标为奇数的标为true,下标为偶数的标为false.     2.然后: 
      for( i=3; i<=sqrt(n); i+=2 )       {   if(prime) 
          for( j=i+i; j<=n; j+=i ) prime[j]=false;       } 
    3.最后输出bool数组中的值为true的单元的下标,就是所求的n以内的素数了。 
    原理很简单,就是当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) 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))的算法。


另外,对于这样的筛法,还可以进一步优化,就是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)内的素数求 
出来,用已经求得的素数来筛出后面的合数。 
我把一般的筛选法的过程详细的叙述了一遍,应该都懂了吧?后面的优化过程及不同的方法,能看懂最好。不是很难的。

相关文章推荐

求小于一个数的所有素数

  • 2015年10月30日 18:07
  • 666B
  • 下载

使用c语言完成了一个求素数的程序

有题目要求完成一款"求素数"的程序,由于之前有思考过这个问题,此程序求"千万内"素数不挂...
  • dalerkd
  • dalerkd
  • 2015年03月15日 09:51
  • 1622

j筛选法求素数

  • 2012年12月29日 08:26
  • 567B
  • 下载

web源代码,求素数

  • 2013年05月10日 10:34
  • 815B
  • 下载

hdu 2682 Tree 最小生成树~~~~水题一枚,,用到了筛法求素数,我竟然在格式上面PE了两次!!

Problem Description There are N (2

C#简易GUI求素数

  • 2012年11月04日 10:41
  • 2.15MB
  • 下载

基于C++的求素数

  • 2012年03月19日 15:44
  • 569B
  • 下载

筛法高效求素数

【问题描述】:    试编写一个程序,找出2->N之间的所有质数。希望用尽可能快的方法实现。 【问题分析】:    这个问题可以有两种解法:一种是用“筛子法”,另一种是“除余法”。    如果...

求素数的另类解法

  • 2013年06月17日 19:09
  • 899B
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:求素数
举报原因:
原因补充:

(最多只允许输入30个字)