筛子法(sieve)求质数,算法书上如是说:前几年比较好的算法的复杂度为o(n),空间复杂度为o(n^(1/2)/logn).另外还有时间复杂度为o(n/logn),但空间复杂度为O(n/(lognloglogn))的算法。
另外,对于这样的筛法,还可以进一步优化,就是bool型数组里面只存奇数不存偶数。
第 1 步 把14个单元赋为true (每个单元代表的数是2*i+3,如第0单元代表3,第1单元代表5...)
第 2 步开始:
i=0; 由于prime[0]=true, 把 [3], [6], [9], [12]标为false. (数字递增为2(2i+3),所以下标递增为2i+3)
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开始筛的。(即若prime[i]为true,则数为2i+3,然后从数(2i+3)2开始筛,即下标从2i2+6i+3开始筛,下标步进为2i+3)
这个优化也对算法复杂度的降低起到了很大的作用。相比于一般的筛法,加入这两个优化后的筛法要高效很多。在数量级更大的情况下就可以发现一般筛法和优化后的筛法的明显区别。
这上面的所有的素数筛选的算法都可以再进一步化为二次筛选法,就是欲求n以内的素数,就先把sqrt(n)内的素数求出来,用已经求得的素数来筛出后面的合数。
相关知识:
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的偶数都是一个素数和只有两个素数因数的合数的和。国际上称为陈氏定理。
【质数的个数】
有近似公式: x 以内质数个数约等于 x / ln(x)
ln是自然对数的意思。
准确的质数公式尚未给出。
10 以内共 4 个质数。
100 以内共 25 个质数。
1000 以内共 168 个质数。
10000 以内共 1229 个质数。
100000 以内共 9592 个质数。
1000000 以内共 78498 个质数。
10000000 以内共 664579 个质数。
100000000 以内共 5761455 个质数。
这个质数分布公式有一定的误差(通常小于15%)。为了保险起见,把反推出的素数分布范围再稍微扩大15%,应该就足够了。