好的,这个问题有点奇怪,但我想知道我是否可以这样做。
我正在研究一个简单的Fibonacci数字生成器,因为我对编程感兴趣。 所以我把它写出来了:
def f(n):
if n == 1: return 1
if n == 2: return 2
else:
return f(n-1) + f(n-2)
并且运行速度非常慢,需要15秒才能在我的计算机上执行f(30)
。
所以我写了这个:
def f(n):
global a
if n == 1: return 1
if n == 2: return 1
else:
if "fib(%s)" % n in a:
return a["fib(%s)" % n]
else:
z = f(n-1) + f(n-2)
a["fib(%s)" % n] = z
return z
基本上将以前的结果存储在如下的字典中:
{'f(1)':1,'f(2)':2,'f(3)':3,'f(4)':5}
等等。在函数中,它将检查该结果是否在该字典中,然后只使用它而不必重做所有计算。
这使得它更快。我可以做f(100)
并立即出现。按照500的间隔,我到了f(4000)
,它仍然是瞬间的。一个问题是这本词典变得非常愚蠢。
所以我在函数的末尾加了a = {}
,但是没有用;它仍然留下a
作为一个大规模的词典。
这样做:
def f(n):
global a
if n == 1: return 1
if n == 2: return 1
else:
if "fib(%s)" % n in a:
return a["fib(%s)" % n]
else:
z = f(n-1) + f(n-2)
a["fib(%s)" % n] = z
return z
a = {}
没有工作。但如果我这样做:
def f(n):
global a
if n == 1: return 1
if n == 2: return 1
else:
if "fib(%s)" % n in a:
return a["fib(%s)" % n]
else:
z = f(n-1) + f(n-2)
a["fib(%s)" % n] = z
return z
# now run the function
f(100)
a = {}
a
重置为空字典。为什么会发生这种情况,我该如何解决?
答案 0 :(得分:3)
函数中的a = {}
语句从未被执行过;在此之前,每个可能的执行路径都会达到return
。如果它被执行了,你就不会喜欢结果 - 它会在每次递归调用函数时执行,这意味着你的字典永远不会包含多个项目!你会以某种方式检测最外面的调用,只清除那里的字典,或者(更简单)在递归之外清除它,就像你的第二个例子一样。
请注意,字典的大部分内容来自使用长字符串键的奇怪决定。用数字本身(如在a[n] = z
中)键入它会使它更加紧凑。
(供将来参考:您在此处提出的保存先前函数调用结果的技术称为" memoization"。)
答案 1 :(得分:0)
尽管有你的问题,你真正想要的是一种更快速的计算Fibonacci序列的方法,对吧?原始方法的问题在于,尽管非常优雅且编码速度快,但重复发生的速度非常慢。 Fibonacci序列具有紧密的形式解决方案。您应该直接进行数学运算以加快代码速度。 按照惯例,将Fibonacci序列F(i)视为:F(0)= 0,F(1)= 1,F(k)= F(k-1)+ F(k-2)k = 2,3 ,...这个序列的解决方案是(我不会在这里展示它,因为它不是那个地方)F(k)=(1 / sqrt(5))*(a ^ k - b ^ k),其中a =(1 + sqrt(5))/ 2和b =(1 - sqrt(5))/ 2。 因此,您可以像这样实现代码:
def f(n):
a = (1 + 5**.5)/2
b = (1 - 5**.5)/2
F = (a**n - b**n)/5**.5
F = int(round(F)) #necessary to get an integer without the decimal part of the approximation. Afterall, you are working with irrational numbers.
return F
此代码非常适用于n的大值。