前面有篇文章,描述了斐波那契数列,如何用迭代器或生成器来生成。CSDNhttps://mp.csdn.net/mp_blog/creation/editor/130422623
实际上,对于这种简单问题,这种实现是为了说明迭代器、生成器的基本使用方法。如果考虑到在编程中就事论事地解决问题。我们还有递归和直接推算等方法。
#### 斐波那契数列的多种实现
import time
# 1, 使用Python生成器来实现
def fibonacci_generator(n):
a, b = 1, 1
for _ in range(n):
yield a
a, b = b, a+b
# 2, 使用暴力解法来实现
def fibonacci_noskill(n):
if n <= 2:
return None
result = []
result.append(1)
result.append(1)
for i in range(2,n):
result.append(result[i-1] + result[i-2])
return result
# 3, 使用辅助递归函数来实现
def fibonacci_recursion(n):
result = []
result.append(1)
result.append(1)
def helper(m, num):
if m == 0:
return
num.append(num[-2]+num[-1])
m -= 1
helper(m, num)
helper(n-2, result)
return result
# 4, 用迭代器来实现
class Solution(object):
def __init__(self):
self.a, self.b = 1, 1
def __iter__(self):
return self
def __next__(self):
self.a, self.b = self.b, self.a + self.b
return self.a
# 5, 另一种递归
def fib(n):
if n <= 0:
return 0
elif n == 1 or n == 2:
return 1
else:
return fib(n-1) + fib(n-2)
if __name__ == "__main__":
start_time = time.perf_counter()
print(list(fibonacci_generator(40)))
end_time = time.perf_counter()
execution_time = (end_time - start_time) * 1000
print(f"使用生成器,执行时间为: {execution_time} 毫秒\n\n")
start_time = time.perf_counter()
print(fibonacci_noskill(40))
end_time = time.perf_counter()
execution_time = (end_time - start_time) * 1000
print(f"使用暴力解法,执行时间为: {execution_time} 毫秒\n\n")
start_time = time.perf_counter()
print(fibonacci_recursion(40))
end_time = time.perf_counter()
execution_time = (end_time - start_time) * 1000
print(f"使用一次递归(函数内建一个辅助递归函数),执行时间为: {execution_time} 毫秒\n\n")
s = Solution()
result = []
result.append(1)
start_time = time.perf_counter()
for e in s:
if e > 102334156:
break
else:
result.append(e)
print(result)
end_time = time.perf_counter()
execution_time = (end_time - start_time) * 1000
print(f"使用迭代器执行时间为: {execution_time} 毫秒\n\n")
start_time = time.perf_counter()
print(fib(40))
end_time = time.perf_counter()
execution_time = (end_time - start_time) * 1000
print(f"使用全递归,执行时间为: {execution_time} 毫秒\n\n")
结果是:
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578, 5702887, 9227465, 14930352, 24157817, 39088169, 63245986, 102334155]
使用生成器,执行时间为: 0.09039998985826969 毫秒
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578, 5702887, 9227465, 14930352, 24157817, 39088169, 63245986, 102334155]
使用暴力解法,执行时间为: 0.05389994475990534 毫秒
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578, 5702887, 9227465, 14930352, 24157817, 39088169, 63245986, 102334155]
使用一次递归(函数内建一个辅助递归函数),执行时间为: 0.058999983593821526 毫秒
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578, 5702887, 9227465, 14930352, 24157817, 39088169, 63245986, 102334155]
,使用迭代器执行时间为: 0.03929995000362396 毫秒
102334155
使用全递归,执行时间为: 44740.48379994929 毫秒
分析_1:
运行是在一台比较老的Thinkpad PC上。
结果都是n为40的斐波那契数列的生成, [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578, 5702887, 9227465, 14930352, 24157817, 39088169, 63245986, 102334155]。
可以看到,迭代器最快,暴力解法次之,生成器可能因为每次的yield等待稍慢。内建递归实现的一次递归,效率尚可。以上都在耗时0.1 毫秒的量级以内。但另外一种全递归方式,引起指数级别的压栈操作,用时高达44秒,比最快的迭代器,用时1,000,000倍。
实验2:
把n 设为100,结果为
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578, 5702887, 9227465, 14930352, 24157817, 39088169, 63245986, 102334155, 165580141, 267914296, 433494437, 701408733, 1134903170, 1836311903, 2971215073, 4807526976, 7778742049, 12586269025, 20365011074, 32951280099, 53316291173, 86267571272, 139583862445, 225851433717, 365435296162, 591286729879, 956722026041, 1548008755920, 2504730781961, 4052739537881, 6557470319842, 10610209857723, 17167680177565, 27777890035288, 44945570212853, 72723460248141, 117669030460994, 190392490709135, 308061521170129, 498454011879264, 806515533049393, 1304969544928657, 2111485077978050, 3416454622906707, 5527939700884757, 8944394323791464, 14472334024676221, 23416728348467685, 37889062373143906, 61305790721611591, 99194853094755497, 160500643816367088, 259695496911122585, 420196140727489673, 679891637638612258, 1100087778366101931, 1779979416004714189, 2880067194370816120, 4660046610375530309, 7540113804746346429, 12200160415121876738, 19740274219868223167, 31940434634990099905, 51680708854858323072, 83621143489848422977, 135301852344706746049, 218922995834555169026, 354224848179261915075]
使用生成器,执行时间为: 0.0798000255599618 毫秒
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578, 5702887, 9227465, 14930352, 24157817, 39088169, 63245986, 102334155, 165580141, 267914296, 433494437, 701408733, 1134903170, 1836311903, 2971215073, 4807526976, 7778742049, 12586269025, 20365011074, 32951280099, 53316291173, 86267571272, 139583862445, 225851433717, 365435296162, 591286729879, 956722026041, 1548008755920, 2504730781961, 4052739537881, 6557470319842, 10610209857723, 17167680177565, 27777890035288, 44945570212853, 72723460248141, 117669030460994, 190392490709135, 308061521170129, 498454011879264, 806515533049393, 1304969544928657, 2111485077978050, 3416454622906707, 5527939700884757, 8944394323791464, 14472334024676221, 23416728348467685, 37889062373143906, 61305790721611591, 99194853094755497, 160500643816367088, 259695496911122585, 420196140727489673, 679891637638612258, 1100087778366101931, 1779979416004714189, 2880067194370816120, 4660046610375530309, 7540113804746346429, 12200160415121876738, 19740274219868223167, 31940434634990099905, 51680708854858323072, 83621143489848422977, 135301852344706746049, 218922995834555169026, 354224848179261915075]
使用暴力解法,执行时间为: 0.05619996227324009 毫秒
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578, 5702887, 9227465, 14930352, 24157817, 39088169, 63245986, 102334155, 165580141, 267914296, 433494437, 701408733, 1134903170, 1836311903, 2971215073, 4807526976, 7778742049, 12586269025, 20365011074, 32951280099, 53316291173, 86267571272, 139583862445, 225851433717, 365435296162, 591286729879, 956722026041, 1548008755920, 2504730781961, 4052739537881, 6557470319842, 10610209857723, 17167680177565, 27777890035288, 44945570212853, 72723460248141, 117669030460994, 190392490709135, 308061521170129, 498454011879264, 806515533049393, 1304969544928657, 2111485077978050, 3416454622906707, 5527939700884757, 8944394323791464, 14472334024676221, 23416728348467685, 37889062373143906, 61305790721611591, 99194853094755497, 160500643816367088, 259695496911122585, 420196140727489673, 679891637638612258, 1100087778366101931, 1779979416004714189, 2880067194370816120, 4660046610375530309, 7540113804746346429, 12200160415121876738, 19740274219868223167, 31940434634990099905, 51680708854858323072, 83621143489848422977, 135301852344706746049, 218922995834555169026, 354224848179261915075]
使用一次递归(函数内建一个辅助递归函数),执行时间为: 0.06530003156512976 毫秒
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578, 5702887, 9227465, 14930352, 24157817, 39088169, 63245986, 102334155, 165580141, 267914296, 433494437, 701408733, 1134903170, 1836311903, 2971215073, 4807526976, 7778742049, 12586269025, 20365011074, 32951280099, 53316291173, 86267571272, 139583862445, 225851433717, 365435296162, 591286729879, 956722026041, 1548008755920, 2504730781961, 4052739537881, 6557470319842, 10610209857723, 17167680177565, 27777890035288, 44945570212853, 72723460248141, 117669030460994, 190392490709135, 308061521170129, 498454011879264, 806515533049393, 1304969544928657, 2111485077978050, 3416454622906707, 5527939700884757, 8944394323791464, 14472334024676221, 23416728348467685, 37889062373143906, 61305790721611591, 99194853094755497, 160500643816367088, 259695496911122585, 420196140727489673, 679891637638612258, 1100087778366101931, 1779979416004714189, 2880067194370816120, 4660046610375530309, 7540113804746346429, 12200160415121876738, 19740274219868223167, 31940434634990099905, 51680708854858323072, 83621143489848422977, 135301852344706746049, 218922995834555169026, 354224848179261915075]
使用迭代器执行时间为: 4.075199947692454 毫秒
生成 这样的数列,[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578, 5702887, 9227465, 14930352, 24157817, 39088169, 63245986, 102334155, 165580141, 267914296, 433494437, 701408733, 1134903170, 1836311903, 2971215073, 4807526976, 7778742049, 12586269025, 20365011074, 32951280099, 53316291173, 86267571272, 139583862445, 225851433717, 365435296162, 591286729879, 956722026041, 1548008755920, 2504730781961, 4052739537881, 6557470319842, 10610209857723, 17167680177565, 27777890035288, 44945570212853, 72723460248141, 117669030460994, 190392490709135, 308061521170129, 498454011879264, 806515533049393, 1304969544928657, 2111485077978050, 3416454622906707, 5527939700884757, 8944394323791464, 14472334024676221, 23416728348467685, 37889062373143906, 61305790721611591, 99194853094755497, 160500643816367088, 259695496911122585, 420196140727489673, 679891637638612258, 1100087778366101931, 1779979416004714189, 2880067194370816120, 4660046610375530309, 7540113804746346429, 12200160415121876738, 19740274219868223167, 31940434634990099905, 51680708854858323072, 83621143489848422977, 135301852344706746049, 218922995834555169026, 354224848179261915075]
分析_2:
这次看到,n从 40 -> 100,其他方法时间量级变化不大,但迭代器明显变慢。从0.0x 个毫秒,到几个毫秒的量级。这是什么原因呢?同时,指数级别的递归调用的危害作用更加明显,通过启停这个Python程序,可以看到CPU占到100%。
总结:
所以从效率而言,如果n 很大,递归方法最要谨慎,尤其是可能递归函数中调用超过一次的递归情况,因为占用大量栈空间,一次算完,可能引起指数增长的递归调用。其次是直接暴力解法,暴力解法并不是不可以用,具体情况具体分析。而生成器、迭代器是基于单值, 从时间、空间角度考虑。可能更优,其中生成器是基于函数的单值生成,更轻量快速;而迭代器,在处理复杂数据结构的时候,可能优势就显现出来了。
BTW,关于递归,写过一篇小文,可以参考。 CSDNhttps://mp.csdn.net/mp_blog/creation/editor/142356275