python递归内存不足

python递归内存不足,python,memory,recursion,out-of-memory,Python,Memory,Recursion,Out Of Memory,当这段代码运行时,OSX通知我应用程序内存不足,并暂停应用程序。Python使用的空间量很快就突破了10 Gig。这段代码永远不会达到Python的最大递归级别,在最坏的情况下,它应该只达到525,但由于缓存,它应该小得多。我有一种感觉,列表链在每一级递归中都被复制,但它似乎是一个全局变量,应该与collatz()的每次调用共享。我在stackoverflow上寻找过类似的问题,但没有找到任何相同的问题 # The following iterative sequence is defined

当这段代码运行时,OSX通知我应用程序内存不足,并暂停应用程序。Python使用的空间量很快就突破了10 Gig。这段代码永远不会达到Python的最大递归级别,在最坏的情况下,它应该只达到525,但由于缓存,它应该小得多。我有一种感觉,列表链在每一级递归中都被复制,但它似乎是一个全局变量,应该与collatz()的每次调用共享。我在stackoverflow上寻找过类似的问题,但没有找到任何相同的问题

# The following iterative sequence is defined for the set of positive integers:
#  n = n/2  (n is even)
#    = 3n+1 (n is odd)
# Using the rule above and starting with 13, we generate the following sequence:
#  13,40,20,10,5,16,8,4,2,1
# It can be seen that this sequence (starting at 13 and finishing at 1) contains 10 
#  terms. Although it has not been proved yet (Collatz Problem), it is thought that
#  all starting numbers finish at 1.
# Which starting number, under one million, produces the longest chain?
# Comments: I'm using dynamic programming to avoid computing the same values over and over
#            again.

lim = 1000000
chain = [1,1]
maxL = 0

def collatz(i):
   if i >= len(chain): chain.extend([None]*(i-len(chain)+1))
   if chain[i] == None: chain[i] = 1 + collatz(i/2 if i%2==0 else 3*i+1)
   return chain[i]

for i in range(1, lim): 
   maxL = i if (collatz(i) > chain[maxL]) else maxL 
   print i, chain[maxL]
print "collatz chain of {} is {} terms long.".format(maxL, collatz(maxL))

编辑:请在此处查看我的工作字典实现:。

若要查看内存错误,请使用limit=100运行代码,然后打印出来

也许您想序列化递归代码:

lengths = {1: 1}

def collatz(i):
    i0 = i
    acc = 0
    while True:
        if i in lengths:
            lengths[i0] = acc + lengths[i]
            return acc + lengths[i]
        acc += 1
        i = (i * 3 + 1) if i % 2 else i // 2

longest = 1
for i in range(1, 1000000):
    c = collatz(i)
    if c > longest:
        longest = c
        print(i, c)
这当然仍然可以在许多方面进行优化,但它会在4秒钟内产生预期的结果


编辑:

您的方法创建一个列表,其长度为有史以来达到的最高期限。对于limit=100,这是9232。这不算多。但对于limit=1000000,它是56991483520(链从704511开始),这是一个相当大的数字。如果它只是int32上的一个数组,那么它的内存就已经是212GB了,事实上它还不止这些


这是一条麻烦的链条:704511、2113534、1056767、3170302、1585151、4755454、2377727、7133182、3566591、10699774、5349887、16049662、8024831、24074494、12037247、36111742、18055871、54167614、27083807、81251422、40625711、121877134、60938567、182815702、91407851、274223554、137111777、41133332、56666、102387503, 77125375, 231376126, 115688063, 347064190, 173532095, 520596286, 260298143, 780894430, 390447215, 1171341646, 585670823, 1757012470, 878506235, 2635518706, 1317759353, 3953278060, 1976639030, 988319515, 2964958546, 1482479273, 4447437820, 2223718910, 1111859455, 3335578366, 1667789183, 5003367550, 2501683775, 7505051326, 3752525663, 11257576990,5628788495、16886365486、8443182743、25329548230、12664774115、37994322346、18997161173、56991483520、28495741760、14247870880、71239354440、3561967720、1780983860、890491930、44525965、13357837896、667868948、333934444444474、166967237、500901712、250450856、225428、62612714、3063535767、237942、, 2934971, 8804914, 4402457, 13207372, 6603686, 3301843, 9905530, 4952765, 14858296, 7429148, 3714574, 1857287, 5571862, 2785931, 8357794, 4178897, 12536692, 6268346, 3134173, 9402520, 4701260, 2350630, 1175315, 3525946, 1762973, 5288920, 2644460, 1322230, 661115, 1983346, 991673, 2975020, 1487510, 743755, 2231266, 1115633, 3346900, 1673450, 836725, 2510176, 1255088, 627544, 313772, 156886, 78443, 235330, 117665, 352996, 176498, 88249, 264748, 132374, 66187, 198562, 99281, 297844, 148922, 74461, 223384, 111692, 55846, 27923, 83770, 41885, 125656, 62828, 31414, 15707, 47122, 23561, 70684, 35342, 17671, 53014, 26507, 79522, 39761, 119284, 59642, 29821, 89464, 44732, 22366, 11183, 33550, 16775, 50326, 25163, 75490, 37745, 113236, 56618, 28309, 84928, 42464, 21232, 10616, 5308, 2654, 1327, 3982, 1991, 5974, 2987, 8962, 4481, 13444, 6722, 3361, 10084, 5042, 2521, 7564, 3782, 1891, 5674, 2837, 8512, 4256, 2128, 1064, 532, 266, 133, 400, 200, 100, 50, 25, 76, 38, 19, 58, 29, 88, 44, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2,一,


使用精确的递归思想,但使用dict(稀疏)而不是list(毫无问题地运行):


列表实现使用了大量的额外内存(正如Hyperboreus所指出的,谢谢!)。切换到字典将内存使用量从~212GB减少到~70MB(32字节整数),并在两秒钟内解决了问题

lim = 1000000
chain = {1:1} 
maxL = 1

def collatz(i):
   if i not in chain: chain[i] = 1 + collatz(i/2 if i%2==0 else 3*i+1)
   return chain[i]

for i in range(1, lim): maxL = i if (collatz(i) > chain[maxL]) else maxL 
print "collatz chain of {} is {} terms long.".format(maxL, collatz(maxL))

我编辑了我的答案,在最后一段中,我解释了你的记忆问题的来源。我更喜欢与Euler项目问题相关的问题和代码是否与问题演示和讨论联系在一起(并对术语进行搜索友好引用,如本例中的“冰雹”):我完全低估了“无”值在列表实现中消耗的额外内存量。谢谢。@brozak看到我最后一次编辑,它完全实现了你的想法,只是使用了一个dict而不是列表。在你指出列表问题后,我还使用了一个字典来实现它:。再次感谢。
lim = 1000000
chain = {1:1} 
maxL = 1

def collatz(i):
   if i not in chain: chain[i] = 1 + collatz(i/2 if i%2==0 else 3*i+1)
   return chain[i]

for i in range(1, lim): maxL = i if (collatz(i) > chain[maxL]) else maxL 
print "collatz chain of {} is {} terms long.".format(maxL, collatz(maxL))