我正在努力找出这个递归函数中n为10,000的运算时间:
def fib3(n):
if n<3:
return 1
else:
return fib3(n-1) + fib3(n-2) + fib3(n-3)
我理解循环中很容易说出运行时间是什么 - 它是循环的数量,但我们如何在递归中执行此操作?
答案 0 :(得分:1)
如果您按照这样设置代码
from collections import Counter
c = Counter()
def fib3(n):
c[n] += 1
if n < 9980:
return 1
else:
return fib3(n-1) + fib3(n-2) + fib3(n-3)
fib3(10000)
print c
你会得到这样的结果
Counter({9979: 223317, 9978: 187427, 9977: 121415, 9980: 121415, 9981: 66012, 9982: 35890, 9983: 19513, 9984: 10609, 9985: 5768, 9986: 3136, 9987: 1705, 9988: 927, 9989: 504, 9990: 274, 9991: 149, 9992: 81, 9993: 44, 9994: 24, 9995: 13, 9996: 7, 9997: 4, 9998: 2, 9999: 1, 10000: 1})
忽略小于9980的键的值,您已经可以看到,n
每个n
的通话次数大约翻倍
所以你可以估计复杂度为O(2 n )(它实际上是关于 O(1.839 n ))
如果你想计算确切的通话次数,你应该尝试写一个递归函数,比如fib3_count(n)
,它返回计算fib3(n)
所需的通话次数
修改强>
计算big-O复杂度可以通过求解这个等式来完成
x**3 - x**2 - x**1 - 1 == 0
复杂度为O(x n )
等式的3个根是
x1 = 1.8392867552141612
x2 = (-0.41964337760708065+0.6062907292071992j)
x3 = (-0.41964337760708065-0.6062907292071992j)
由于x必须是实数,我们留下:O(1.8392867552141612 n )
答案 1 :(得分:1)
这是指数时间。如果fib3(i)
显示fib3(k)
的运行速度比i < k
快,则可以直接显示,因为计算fib3(k)
将涉及计算fib3(i)
,可能需要多次。计算fib3(n+3)
需要计算fib3(n+2)
,fib3(n+1)
和fib3(n)
;因此,它至少需要计算fib3(n)
的3倍。通过归纳,您可以证明fib3(n)
至少花费O(3^(n/3))
时间进行计算。更复杂的分析可以给出渐近精确的界限。
答案 2 :(得分:0)
在每次递归通话中,您都会进行3次额外通话。它与二叉树非常相似,但是它们有2个子节点,完整二叉树中的子节点总数为pow(2,n)。
这里有3个流量转移,这使得O(3^n)
修改强>
以下是一些代码:
import math
class F:
def __init__(self):
self.c = 0
def fib3(self, n):
self.c += 1
if n < 3:
return 1
else:
return self.fib3(n-1) + self.fib3(n-2) + self.fib3(n-3)
f = F()
f.fib3(20)
print f.c
输出将是:
128287
print math.pow(3, 20)
评估为3486784401.这是高估的,但这是由于fib3可以减少3而不是1来确定。
如果您运行以下代码,并且始终在n-1上调用fib3,您将获得O(3^n)
import math
class F:
def __init__(self):
self.c = 0
def fib3(self, n):
if n < 1:
return 1
else:
self.c += 1
return self.fib3(n-1) + self.fib3(n-1) + self.fib3(n-1)
f = F()
f.fib3(10)
print f.c
实际上你会得到O((3^n) / 2)
,但这里有两个因素,所以它只是O(3^n)