斐波那契数列递归优化

背景:今天看网课提到了斐波那契数列使用递归效率过低的问题,于是自己写代码使用递归求第100项,出去吃完早饭回来还没跑完。。。好吧,需求来了,我们来开始优化吧!😅

1、原代码

def fibonacci(n):
	if n == 1 or n == 2:
		return 1
	else:
		return fibonacci(n - 1) + fibonacci(n - 2)

2、改进

两种办法,本质上都是把先前函数运行的结果存起来,下一次需要调用时候直接使用。

第一种是装饰器,args[0]即是被装饰函数的参数(因为fibonacci函数只有一个参数,故可以这么写,也可以用关键字参数的方式,或者直接命名为n,都是可以的),可以看到每次被装饰函数被调用后都会把结果以 param:result 的方式存与字典,后续调用可以直接从字典获取,从而避免了重复的计算。

from functools import wraps


def cache(func):
	d = dict()

	@wraps(func)
	def wrapper(*args):
		if args[0] not in d:
			res = func(args[0])
			d[args[0]] = res

		return d[args[0]]

	return wrapper

第二种是使用队列,每次计算时将队头两个元素出队,计算其和,即为本次运行的结果。最后将上一次运算结果和本次结果追加到队尾,作为下一次运算的参数,执行n-2次后,队尾巴元素即为所求。

from collections import deque


def fibonacci_no_recursion(n):
	q = deque([1, 1])
	if n <= 2:
		return q.pop() + q.pop()

	for i in range(n - 2):
		a1 = q.popleft()
		a2 = q.popleft()
		q.append(a2)
		q.append(a1 + a2)

	return q.pop()

3、运行

可见非递归最快,递归加缓存的次之,二者在输入为30时的耗时尚在同一量级,而改进前的则是成千上万倍的效率差距,随着数字增大,这个差距会呈指数级别的增大。

4、完整代码

from collections import deque
from functools import wraps
import time


def cache(func):
	d = dict()

	@wraps(func)
	def wrapper(*args):
		if args[0] not in d:
			res = func(args[0])
			d[args[0]] = res

		return d[args[0]]

	return wrapper


def time_delta(func):
	@wraps(func)
	def wrapper(*args, **kwargs):
		t1 = time.time() * 1000
		res = func(*args, **kwargs)
		t2 = time.time() * 1000
		print(': '.join([func.__name__, str(t2 - t1) + 'ms']))
		return res

	return wrapper


# 原始递归数列
def fibonacci_2(n):
	if n == 1 or n == 2:
		return 1
	else:
		return fibonacci_2(n - 1) + fibonacci_2(n - 2)


@time_delta
def fibonacci_original(n):
	return fibonacci_2(n)


# 加缓存的递归数列
@cache
def fibonacci(n):
	if n == 1 or n == 2:
		return 1
	else:
		return fibonacci(n - 1) + fibonacci(n - 2)


@time_delta
def fibonacci_with_cache(n):
	return fibonacci(n)


# 队列实现的非递归数列
@time_delta
def fibonacci_with_queue(n):
	q = deque([1, 1])
	if n <= 2:
		return q.pop() + q.pop()

	for i in range(n - 2):
		a1 = q.popleft()
		a2 = q.popleft()
		q.append(a2)
		q.append(a1 + a2)

	return q.pop()


if __name__ == '__main__':
	num = int(input("请输入n: "))
	print('result: ', fibonacci_original(num), end='\n\n')
	print('result: ', fibonacci_with_cache(num), end='\n\n')
	print('result: ', fibonacci_with_queue(num))

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值