你的第一个初筛部分完全没问题。只有第二因素发现部分应该被纠正。
在第二部分中,您应该除以素数,而不仅仅是一次,而是多次,直到它仍然可以整除。这将确保您考虑所有主要因素的权力。
第二部分称为素数试除法。众所周知,仅通过以下除数进行试除就足够了Sqrt(N)
。N 的剩余值也将自动成为素数。
对您的算法的另一项非常重要的速度改进是它足以使筛子尺寸变大Sqrt(N)
,而不是N
。因为我们只需要小于 的素数Sqrt(N)
。这是因为经过试除后剩余N
的自动变成素数。
我还为您的筛分部分发现了一项改进,您应该替换for i in range(x + x, ...
为for i in range(x * x, ...
. 因为你可以根据埃拉托色尼筛的经典算法,x + x
而不是从开始筛分。这将进一步提高速度。从开始是可以的,但也会给出正确的结果和更好的性能。x * x
x + x
x * x
一个更明显的改进是当你想分解多个数字时,你可以多次重用和扩展筛子,这将使代码更快。当重用筛子时,最好将得到的素数保存在一个单独的列表中,这样在第二个审判阶段你不会迭代整个筛子而只迭代素数,这又会加快速度。我没有在下面的代码中进行这两项改进,但是如果您愿意,我可以做到,请告诉。
完整更正的最终版本是:
在线尝试!
def factorize(n):
sieve = [True] * int(n ** 0.5 + 2)
for x in range(2, int(len(sieve) ** 0.5 + 2)):
if not sieve[x]:
continue
for i in range(x * x, len(sieve), x):
sieve[i] = False
factors = []
for i in range(2, len(sieve)):
if i * i > n:
break
if not sieve[i]:
continue
while n % i == 0:
factors.append(i)
n //= i
if n > 1:
factors.append(n)
return factors
print(factorize(99020)) # [2, 2, 5, 4951]
输入:
99020
输出:
[2, 2, 5, 4951]
如果您只需要分解几个数字,那么在没有中间筛选阶段的情况下进行Trial Division Factorization可能会更快。这也使代码更简单、更短。
下面是在没有筛选阶段的情况下进行分解的完整代码。
在这段代码中,我通过只尝试奇数除数做了一个明显的速度改进,这将使总算法速度加倍。当然,要做到这一点,您需要先排除 2 的所有幂,我也这样做了。
在线尝试!
def factorize(n):
factors = []
while (n & 1) == 0:
factors.append(2)
n >>= 1
for d in range(3, 1 << 60, 2):
if d * d > n:
break
while n % d == 0:
factors.append(d)
n //= d
if n > 1:
factors.append(n)
return factors
print(factorize(99020)) # [2, 2, 5, 4951]