我练习编写针对空间或时间复杂度进行优化的算法。使用优质筛,至少您必须存储所有找到的素数列表。似乎与发现的素数成比例的数据是这种算法可能使用的最小空间量。
From Wikipedia about the sieve of Atkin - 我不确定的是,当素数超过此值时,筛子如何使用O(n ^ 1/2)空间。这就是为什么它似乎至少必须与质数的数量成比例。我是否将可数数字与空间复杂性混为一谈?
In this paper on the sieve of Atkin,他们的算法打印"素数高达N ...这里“记忆”不包括打印机使用的纸张。"这似乎是对空间的不公平计算。
def prime_sieve(limit):
factors = dict()
primes = []
factors[4] = (2)
primes.append(2)
for n in range(3, limit + 1):
if n not in factors:
factors[n * 2] = (n)
primes.append(n)
else:
prime = factors.get(n)
m = n + prime
while m in factors:
m += prime
factors[m] = (prime)
del factors[n]
return primes
答案 0 :(得分:2)
此算法的空间复杂度为len(numbers) + len(primes)
;列表的大小加上字典的大小。
在这种情况下,算法更糟比你期望的天真素数筛(limit
)。 len(numbers) + len(primes) > limit
因为例如对于prime_sieve(100)
,以下不相关的数字存储在numbers
:
{129: 43, 134: 67, 141: 47, 142: 71, 146: 73, 158: 79, 166: 83, 178: 89, 194: 97, 102: 17, 104: 2, 105: 3, 106: 53, 110: 11, 111: 37, 112: 7, 114: 19, 115: 23, 116: 29, 117: 13, 118: 59, 120: 5, 122: 61, 123: 41, 124: 31}
有几种素数筛,具有不同的时间和空间复杂性;见例如Wikipedia以及How do i reduce the space complexity in Sieve of Eratosthenes to generate prime between a and b?
等问题另请注意,prime = numbers.get(n)
没有必要 - 您已经检查了if n not in numbers
,因此您只需使用prime = numbers[n]
。
答案 1 :(得分:1)
空间复杂度测量非常公平。如果将primes.append(n)
替换为yield n
,并在消费者例程中逐个处理素数而不将它们全部存储,例如查找具有特定属性的素数,则需要存储空间素数本身是O(1),以素数的数量来衡量。
(yield
是构建生成器的Python方式,这是一种协同例程,它向调用者发出值并保存函数的状态,以便它可以重新生成输入。)
答案 2 :(得分:1)
“使用优质筛子,至少你必须存储所有找到的素数列表。”
不正确的。您只需要在下限(包括)上限的平方根下面的素数,以筛选该范围内的素数。
如果您的筛子是增量的,无限制的,那么您只需要在当前生产点的平方根下面(并包括)填充。
怎么可能?通过为“核心”质数(低于sqrt的那些)使用单独的素数供应,完全可以使用相同的函数计算 - 递归。有关示例,请参阅this answer。
不计算生产的素数是完全合法的 - 你可以确实将它们发送到打印机或外部文件等等。因此,这种筛子的空间复杂性将是{{ 1}}对于 n 素数达到 N~ = n * log n 。
另外,不要靠近阿特金的筛子。街上的一句话是,用它来击败Eratosthenes的正确轮式筛子是不可能的(通过GordonBGood搜索关于这个主题的答案,如this one)。< / p>