为什么在Python中,即使没有重复计算,记忆化也可以加速阶乘运算?
这是我的密码为什么在Python中,即使没有重复计算,记忆化也可以加速阶乘运算?,python,algorithm,memoization,Python,Algorithm,Memoization,这是我的密码 import timeit fac_mem = {} def fac(k): if k < 2: return 1 if k not in fac_mem: fac_mem[k] = k*fac(k-1) return fac_mem[k] def fact(k): if k < 2: return 1 return k*fact(k-1) if __name__ == "__main__": print timeit.timeit
import timeit
fac_mem = {}
def fac(k):
if k < 2: return 1
if k not in fac_mem:
fac_mem[k] = k*fac(k-1)
return fac_mem[k]
def fact(k):
if k < 2: return 1
return k*fact(k-1)
if __name__ == "__main__":
print timeit.timeit("fac(7)","from __main__ import fac")
print timeit.timeit("fact(7)","from __main__ import fact")
print timeit.timeit("fac(70)","from __main__ import fac")
print timeit.timeit("fact(70)","from __main__ import fact")
那么,在程序运行之前,dict是空的,为什么记忆仍然加快了阶乘运算?我的意思是,这两个版本的调用次数是相同的。
然后我稍微修改了代码,将dict移到函数中
def fac(k):
fac_mem = {}
if k < 2: return 1
if k not in fac_mem:
fac_mem[k] = k*fac(k-1)
return fac_mem[k]
为什么慢一点?这是因为函数内部生成的值临时存储在堆栈中吗?外部变量是全局变量,但是什么让它如此快速?
请有人帮我清理一下好吗?非常感谢。当您运行
timeit.timeit
而不为关键字number
指定参数时,它将执行您传递给它1000000次的代码。如果在Python的全局范围中保留一个名为fac_mem
的全局字典,它将在该字典中保存第一次执行的结果
因此,您的记忆阶乘函数只会在第一次执行时变慢,因为它实际上必须进行计算。剩下的9999999次,它只需在字典中查找答案,避免进行计算
如果将字典保留在函数中,则每次Python离开函数中的作用域后,字典都会被销毁(因为函数返回时,对字典的所有引用都会被销毁)。因此,词典将无法保存其答案,并且在将来执行时仍将保持缓慢
当您运行
timeit.timeit
而不为关键字number
指定参数时,它将执行您传递给它1000000次的代码。如果在Python的全局范围中保留一个名为fac_mem
的全局字典,它将在该字典中保存第一次执行的结果
因此,您的记忆阶乘函数只会在第一次执行时变慢,因为它实际上必须进行计算。剩下的9999999次,它只需在字典中查找答案,避免进行计算
如果将字典保留在函数中,则每次Python离开函数中的作用域后,字典都会被销毁(因为函数返回时,对字典的所有引用都会被销毁)。因此,词典将无法保存其答案,并且在将来执行时仍将保持缓慢
如果你想测量实际速度,你需要在每次测试调用后清除你的记忆词典。更好的问题:为什么CS采用了可笑的术语记忆?@JeremyWest@christopheoca是的,我理解词源。仅仅因为有理由并不意味着这是一个好理由:)。每次我看到那个词我都会畏缩。看起来像是打字错误@JeremyWest当我几周前得知这件事的时候,一开始我还以为这是个打字错误呢!但后来我终于习惯了,现在我很喜欢这个词更好的问题:为什么CS采用了可笑的术语Memorization?@JeremyWest@Christopherica是的,我理解词源。仅仅因为有理由并不意味着这是一个好理由:)。每次我看到那个词我都会畏缩。看起来像是打字错误@JeremyWest当我几周前得知这件事的时候,一开始我还以为这是个打字错误呢!但后来我终于习惯了,现在我很喜欢这个词谢谢,但是我是否已经通过将dict移动到阶乘函数中获得了实际速度?不,将字典移动到函数中会使其无效,因为它是局部的,并且总是空的。谢谢,但是我是否已经通过将dict移动到阶乘函数中获得了实际速度?不,将字典移动到函数内部会使它无用,因为它是本地的,并且总是空的。
def fac(k):
fac_mem = {}
if k < 2: return 1
if k not in fac_mem:
fac_mem[k] = k*fac(k-1)
return fac_mem[k]
1.92900857225
0.910026658388
25.5475004875
14.2164999769