素数计算常用算法
素数的定义
“质数又称素数。一个大于1的自然数,除了1和它自身外,不能被其他自然数整除的数叫做质数”
1. 试除法(Trial Division)
这是最基本的素数判断方法。判断一个数是否为素数,就是尝试除以所有小于它的整数,若没有整除的情况,则该数为素数。
试除法步骤
- 如果一个数
n能被小于n的某个整数整除,则n不是素数。 - 最多只需要尝试除到
sqrt{n},因为如果n=a×b,那么必有a≤sqrt{n}且b≥sqrt{n},所以只需要检查小于等于sqrt{n} 的数。
- 简单易懂
- 效率较低,特别是当 n 很大时
6k±1法优化的原理
除了 2 和 3 之外,所有素数都可以表示为 6k±1 的形式,其中k是一个整数。这是因为,任何整数 n 都可以写成以下六种形式之一:
6k,6k+1,6k+2,6k+3,6k+4,6k+5
在这些形式中,只有 6k+1 和 6k−1 可能是素数。其他形式都可以被 2 或 3 整除,因此不需要检查。
步骤
在标准的试除法中,通常需要从 2 开始检查每个数是否是素数。但在使用 6k±1 法时,我们可以跳过能被 2 或 3 整除的数,只检查形如 6k±1的数。
具体如下:
- 检查
n是否能被2或3整除。如果可以,直接返回false(不是素数) - 从
5开始,检查n是否能被形如6k±1的数整除,直到sqrt{n}为止
C++代码
1 | bool isPrime(int n) { |
- 时间复杂度:
O(sqrt{n}) - 适用场景: 当
n较小,或者只需要判断一个单独的数是否为素数时,试除法是最直接的选择
2. 埃拉托斯特尼筛法(Sieve of Eratosthenes)
这是一个高效的生成素数的算法,可以用来找出一定范围内的所有素数。
筛法步骤
- 创建一个从
2到某个上限n的列表,初始时假设所有数都是素数 - 从
2开始,标记所有2的倍数为非素数(即删除) - 继续检查下一个未被删除的数,将其倍数删除
- 重复上述过程直到所有小于
sqrt{n} 的数都处理完毕
- 可以高效地找出一段区间内所有的素数
- 时间复杂度为
O(n log log n),比试除法要高效得多
- 对于大范围的素数计算,内存占用较大
C++代码
1 |
|
- 时间复杂度:
O(n log log n) - 适用场景: 生成小于某个数
n的所有素数时,埃拉托斯特尼筛法非常高效。对于处理大量素数查找任务,它的效率远高于试除法。
3. 米勒-拉宾素性测试(Miller-Rabin Primality Test)
这是一种概率性的素性测试算法。它判断一个数是否为素数,虽然它不能保证绝对正确,但通过多次测试可以以极高的概率确定一个数是否为素数。
步骤
- 基于费马小定理:对于一个大素数
p,若随机选择的数a满足ap−1≡1 mod p,则p是素数 - 通过随机选择多个不同的
a,每次执行费马测试,若结果不成立,则n一定不是素数
- 对于大数非常高效
- 可以非常快速地进行素数性检验
- 是概率算法,不能提供确定性的结果(但通过多次实验,可以达到很高的精确度)
C++代码
1 |
|
- 时间复杂度: 每次测试的时间复杂度为
O(log n),进行k次测试,整体复杂度为O(k log n),其中k通常设置为5到10,保证很高的精确度。 - 适用场景: 对于大数素性检测,尤其是在确定性测试需求不高的情况下,米勒-拉宾测试非常高效。通过增加 kkk 次测试可以获得非常高的精度,适用于大数素性判断。
总结
适用于小规模的素数判断
适合生成一段范围内的所有素数
适用于大数的素性测试,具有较高的效率和较高的准确性
最低时间复杂度:埃拉托斯特尼筛法
适合大数素性检测:米勒-拉宾素性测试
因此,如果你需要找出一个区间内的所有素数,埃拉托斯特尼筛法 是最佳选择。如果是对大数的单独素性检测,米勒-拉宾素性测试 会更有效。
本作品由 Pavilion_Cat 于 2024-12-26 13:48:00 发布
作品地址:素数计算常用算法
除特别声明外,本站作品均采用 CC BY-NC-SA 4.0 许可协议,转载请注明来自 Pavilion_Cat's Blog


