关于素数的筛选法

来源:互联网 发布:推荐好的口语书籍 知乎 编辑:程序博客网 时间:2024/05/13 00:40

筛选方法

1. 简单筛选法

回顾前面我们对判断是否为质数的算法所作的最后的改进:如果一个数没有小于它本身的质因子,那么这个数就是质数。不妨从另一个角度考虑,如果我们知道了一些质数,那么显然,这些质数的2倍,3倍,4倍……都不会是质数,我们就可以将这些2倍,3倍,4倍……的数字“筛”去,这就是解本题的另一种方法——“筛选法”。

大致步骤如下:

1)当前最大的质数X2,可能为质数的集合S[3..10000]

2)将X2倍,3倍,4倍……数字从集合S中删去。

3)如果集合S为空,则结束;否则转到(4)。

4)当前最大质数X的值更新为当前集合S中的最小值,返回(2)。

显然,每次从集合S中选取的最小值必定为质数,X的值逐渐增大,集合S逐渐减小。由于集合操作速度慢,且存储量有限,因此,在程序实现中,我们用

ok : array[2..10000] of boolean

来代替集合Sok[i]false表示i不是质数。

对于“筛选法”的改进,主要也体现在两个方面——枚举要筛选的质数和筛选的过程。

2. 要筛选的质数范围的改进

假设要求的质数上限为N,那么显而易见,根据“枚举法”的一个结论,即一个数若不是质数,则必然含有小于 的质因子。因此,“筛选法”所要枚举的质数仅仅限于 的范围内,对于其他大于 的质数,只需打印,无须进行“筛选”。

事实上,本次改进的效果并不是特别明显,因为,大于 的质数即使进行筛选,由于其本身数值大,所以在N范围内可被筛选的数并不是很多。

3. 筛选过程的改进

我们注意到,所有质数,除2以外,都是奇数。换句话说,所有偶数,除2以外,都不是质数。

应用这个性质,我们将2作为特例进行特殊处理后,每次用求得的一个质数(必然为奇数)进行筛选时,不要2倍,3倍,4倍……的筛选了,只要3倍,5倍,7倍……筛选即可(因为奇数×偶数=偶数)。如此,“筛选法”效率从理论上就提高了1倍!

至此,“筛选法”已经被改进得非常优秀了。事实上,“枚举法”和“筛选法”的改进之外还有许多,但编程的复杂度也会随之不断上升!(在竞赛中,求质数仅仅可能是某道题目的一个部分,应用上面的方法就已经足够了)

 

三、枚举法与筛选法的比较

这样,我们求质数时就有了两种不同的方法:“枚举法”和“筛选法”。现在,让我们从理论上来比较它们的运行效率。

“枚举法”对于每个数都要枚举所有小于该数平方根的质数来判断,并根据最后改进的程序运行,比较次数见下表。

上限N

1000

10000

100000

500000

1000000

判断次数

1804

33756

644439

5209011

12927405

比例

11.8

13.4

16.4

110

112

运行时间

0.01s

0.01s

0.50s

4.90s

10.05s

我们看到,随着N的增加,判断次数的增加将是非常惊人的。

“筛选法”是对每个质数(奇数)计算其倍数来筛选。同样根据“筛选法”最后改进的程序运行,“筛选”次数即赋值false的次数,见下表。

上限N

1000

10000

100000

500000

1000000

判断次数

457

5995

71556

391987

811068

比例

10.46

10.60

10.72

10.78

10.81

运行时间

0.01s

0.01s

0.11s

0.38s

0.77s

可见,“筛选法”的效率要大大优于“枚举法”。

虽然在时间效率上,“筛选法”比“枚举法”要强许多,但是,大家可能会发现一个问题,即当上限N非常大的时候,“筛选法”的空间如何能够存储下(需要开一个1Nboolean数组)呢?其实这是可以解决的。

在所开的boolean数组中,只需要记录下奇数的情况,这样原本需筛去数组中a值的357,……倍,而新数组中a=2*i+1,其所处的位置位于i=(a-1) div 2,而其3倍的值则位于(3*aa) div 2iai,同理,其57,……倍的值则分别位于2*ai3*ai,……的位置,这样可以节约一半的空间。

原创粉丝点击