埃拉托色尼筛法 Python & C++

⚡ 智能摘要

埃拉托色尼筛法是一种经典的素数算法,它通过迭代地标记每个素数的倍数来过滤合数,只留下选定上限内的素数以便快速查找。

  • 🔢 核心理念: 从 2 开始标记每个素数的倍数,以分离出小于等于 n 的素数。
  • 🧮 循环边界: 迭代次数只需达到 n 的平方根,因为更大的因子已经被消除。
  • 时间复杂度: 该算法的运行时间为 O(n log log n),对于实际应用范围而言,其时间复杂度接近线性。
  • 分段筛: 将范围分成块,可将辅助内存从 O(n) 减少到 O(√n)。
  • 🧪 用例: 密码学、哈希算法、算法竞赛和数论都依赖于快速生成素数。

埃拉托色尼筛法 Python

什么是埃拉托色尼筛法?

埃拉托色尼筛法是最简单的素数筛法。它是一种用于找出给定范围内所有素数的素数算法。存在几种素数筛法,包括埃拉托色尼筛法、阿特金筛法和桑达拉姆筛法。

这个单词 ”“”指的是一种过滤物质的器具。同样,筛算法在 Python 以及其他语言指的是一种从整数列表中过滤掉质数的方法。

该算法采用迭代方法筛选素数。筛选过程从最小的素数开始。素数是大于 1 的自然数,它只有两个因数,即 1 和它本身。 Numbers 不是质数的数称为合数。

为什么要使用埃拉托色尼筛法?

埃拉托色尼筛法首先选择一个较小的素数,然后过滤掉它的所有倍数。该过程在一个给定的范围内循环运行,高效地生成小于等于 n 的所有素数,而无需对每个候选素数进行试除运算。

这使得素数筛法比逐个检查素数更快。它广泛应用于数论、密码学、哈希算法和算法竞赛等领域,这些领域都需要快速生成大量素数。

例如:

让我们选取 2 到 10 之间的数字范围。

埃拉托斯特尼筛法

应用埃拉托色尼筛法后,将得到质数列表 2、3、5、7。

埃拉托斯特尼筛法

算法 埃拉托斯特尼筛法

以下是埃拉托斯特尼筛选法的算法:

步骤1) 创建一个从 2 到给定范围 n 的数字列表。我们从 2 开始,因为它是最小的质数,也是第一个质数。

步骤2) 选择列表中最小的数字 x(初始 x 等于 2),遍历列表,并通过标记所选数字的所有倍数来筛选相应的合数。

步骤3) 然后选择下一个素数或列表中最小的未标记数字并重复步骤 2。

步骤4) 重复上一步,直到 x 的值小于或等于 n 的平方根 (x<=算法 埃拉托斯特尼筛法).

注意: 数学推理非常简单。数值范围 n 可以分解为:

n = a * b

同样,n = 算法 埃拉托斯特尼筛法 * 算法 埃拉托斯特尼筛法

=(小于的因子 算法 埃拉托斯特尼筛法) * (因子大于 埃拉托斯特尼筛法)

因此至少有一个 主要原因 或者两者必须 <= 算法 埃拉托斯特尼筛法因此,遍历到 算法 埃拉托斯特尼筛法 足够了。

步骤5) 经过这四个步骤后,剩余的未标记数字将是给定范围 n 内的所有质数。

示例

计费示例:

让我们举个例子看看它是如何运作的。

在这个例子中,我们将找出从 2 到 25 的所有质数。所以,n = 25。

步骤1) 第一步,我们将取 2 到 25 之间的数字列表,因为我们选择了 n = 25。

算法 埃拉托斯特尼筛法

步骤2) 然后我们从列表中选择最小的数字 x。初始时 x = 2,因为它是最小的质数。然后我们遍历列表,标记出 2 的倍数。

对于给定的 n 值,2 的倍数有:4、6、8、10、12、14、16、18、20、22、24。

埃拉托斯特尼筛法

注意: 蓝色表示选中的数字,粉色表示排除的倍数。

步骤3) 然后我们选择下一个最小的未标记数字,即 3,并通过标记 3 的倍数重复上一步。

埃拉托斯特尼筛法

步骤4) 我们以同样的方式重复步骤 3,直到 x = 埃拉托斯特尼筛法 或5。

埃拉托斯特尼筛法

步骤5) 其余未标记的数字是 2 到 25 之间的质数。

埃拉托斯特尼筛法

伪Code

以下伪代码描述了埃拉托色尼筛法的基本结构,之后我们将它翻译成实际代码。

Begin
	Declare a boolean array of size n and initialize it to true
	For all numbers i : from 2 to sqrt(n)
     		IF bool value of i is true THEN
         			i is prime
         			For all multiples of i (i<n)
             			mark multiples of i as composite
Print all unmarked numbers
End

埃拉托斯特尼筛法 C/C++ Code 例如:

以下是完整的 C++ 埃拉托色尼筛法的实现,打印出小于等于选定上限的所有素数。

#include <iostream>
#include <cstring>
using namespace std;
void Sieve_Of_Eratosthenes(int n)
{
    // Create and initialize a boolean array
    bool primeNumber[n + 1];
    memset(primeNumber, true, sizeof(primeNumber));
    for (int j = 2; j * j <= n; j++) {
        if (primeNumber[j] == true) {
            // Update all multiples of i as false
            for (int k = j * j; k <= n; k += j)
                primeNumber[k] = false;
        }
    }
    for (int i = 2; i <= n; i++)
        if (primeNumber[i])
            cout << i << " ";
}
int main()
{
    int n = 25;
    Sieve_Of_Eratosthenes(n);
    return 0;
}

输出:

2 3 5 7 11 13 17 19 23

Eratosthenes筛 Python 程序范例

下列 Python 该程序使用布尔列表和 while 循环实现了相同的算法。

def SieveOfEratosthenes(n):
# Create a boolean array
	primeNumber = [True for i in range(n+2)]
	i = 2
	while (i * i <= n):
		if (primeNumber[i] == True):
			# Update all multiples of i as false
			for j in range(i * i, n+1, i):
				primeNumber[j] = False
		i += 1
	for i in range(2, n):
		if primeNumber[i]:
			print(i)
n = 25
SieveOfEratosthenes(n)

输出:

2
3
5
7
11
13
17
19
23

分段筛

我们已经看到,埃拉托色尼筛法遍历整个数域。因此,它需要 O(n) 的内存空间来存储这些数字。当我们试图在一个非常大的数域内寻找素数时,情况就变得复杂了,因为为更大的 n 分配如此大的内存块是不切实际的。

可以通过引入一些新特征来优化算法。其思想是将数字范围划分为更小的部分,然后逐个计算这些部分中的素数。这是一种降低空间复杂度的有效方法。这种方法称为 分段筛。

可以通过以下方式实现优化:

  1. 使用简单的筛子找出 2 至 分段筛 并将它们存储在数组中。
  2. 将范围 [0…n-1] 划分为大小最多为 分段筛.
  3. 对于每个线段,遍历该线段并标记步骤 1 中找到的质数的倍数。此步骤需要 O(分段筛)最多。

常规筛选法需要 O(n) 辅助内存空间,而分段筛选法需要 O(分段筛对于较大的 n 值,这是一个显著的改进。但该方法也有缺点,因为它没有改善时间复杂度。

复杂度分析

了解空间和时间复杂度有助于针对给定的问题规模选择常规筛法还是分段筛法。

空间复杂度:

简单的埃拉托色尼筛法算法需要 O(n) 内存空间。分段筛法需要 O(复杂度分析)辅助空间。

时间复杂度:

常规埃拉托色尼筛法算法的时间复杂度为 O(n*log(log(n)))。其复杂度背后的原因将在下文讨论。

对于给定的数 n,标记一个合数(即非质数)所需的时间是恒定的。因此,循环运行的次数等于:

n/2+n/3+n/5+n/7+……∞

= n * (1/2 + 1/3 + 1/5 + 1/7 +…….∞)

素数之和的调和级数可以推导为 log(log(n)):

(1/2 + 1/3 + 1/5 + 1/7 +…….∞)= log(log(n))

因此,时间复杂度为:

T(n) = n * (1/2 + 1/3 + 1/5 + 1/7 + ……∞)

= n * 对数(对数(n))

因此,时间复杂度为 O(n * log(log(n)))。

接下来,你将学习到…… 帕斯卡的三角形.

常见问题

任何合数 n 都可以写成两个因数的乘积,并且至少有一个因数小于或等于 n 的平方根。标记超出此范围的倍数是没有必要的,因为所有合数都已被排除。

常规筛法需要分配 O(n) 内存来标记每个数字,而分段筛法将范围分割成大小为 √n 的块,从而实现内存复用。当 n 非常大且 RAM 有限时,分段筛法更优。

它的运行时间复杂度为 O(n log log n),接近线性复杂度。在现代笔记本电脑上,生成小于一千万的所有素数只需不到一秒,这使得该筛法成为中小范围素数生成中最快的实用选择。

现代人工智能加速器通过在GPU和TPU上并行执行素数筛选算法来加速大规模素数搜索。机器学习模型还有助于预测有希望的候选范围,从而减轻RSA密钥生成中使用的Miller-Rabin素数检验和其他素数检验的工作负载。

是的。人工智能导师会生成循序渐进的指导。 trac它们可以可视化复合消元过程,提出诸如轮式分解之类的优化方案,并以交互方式解释证明。它们有助于学习者建立对调和级数界限和筛法背后复杂度论证的直觉。

总结一下这篇文章: