Python 嵌套递归是可能的还是应该避免递归?
我遇到了这样一个问题Python 嵌套递归是可能的还是应该避免递归?,python,algorithm,recursion,big-o,Python,Algorithm,Recursion,Big O,我遇到了这样一个问题 F(1)=1 F(2n)=F(n) F(2n+1)=F(n)+F(n+1) 开发一个递归程序来计算F 一些用户提到使用两个递归函数调用: def calc(n): if n=1 : return 1 else if(n%2)==0: return calc(n/2) else : return calc(n/2)+calc(n/2+1) **NESTED RECURSION** 这是正确的逻辑吗?算法不是指数级的大吗? 我想到了一
- F(1)=1
- F(2n)=F(n)
- F(2n+1)=F(n)+F(n+1)
F
一些用户提到使用两个递归函数调用:
def calc(n):
if n=1 :
return 1
else if(n%2)==0:
return calc(n/2)
else :
return calc(n/2)+calc(n/2+1) **NESTED RECURSION**
这是正确的逻辑吗?算法不是指数级的大吗?
我想到了一个简单的代码,如:
def calc(count):
result[1]=1
n=2
for range(1,count):
if n%2=0:
result.append(result[n])
else :
result.append(result[n/2]+result[n/2+1])
return result
递归还不错。将递归看作一种工具。有些问题可以用递归很好地解决(例如斐波那契数),而其他问题没有递归弯曲(工作列表类型的算法) 人们在递归方面出错的原因是,他们认为递归解决方案会给他们带来良好的声誉。我会说,用最简单的方法解决这个问题 有时这种方法是递归的,有时不是
此外,递归方法可能更难理解。因此,您需要考虑可读性。这两种方法都是正确的。一个函数有多个递归调用确实是合法的,其含义是您所想的——只需执行一个调用,然后执行下一个,然后执行下一个,等等 有趣的是,我不认为递归版本会进行指数级的调用。它最多进行两次递归调用,但每次调用的问题大小(大约)是原始调用的一半。从本质上讲,重复性如下所示:
T(1) = 1
T(2) = 1
T(n) <= T(n / 2) + T(n / 2 + 1) + 1
那么让我们设置a=1。对于归纳步骤,我们考虑三种情况。首先,我们考虑楼层(N/2)
时,更容易估计第二个算法的性能:它在空间和时间上明显为O(n),具有较小的常数。但这并不意味着第二种算法比第一种算法快。事实并非如此
在Python 2.6.5中,第二个算法在计算calc(1000)
时比第一个算法慢25倍,在计算calc(10000)
时慢80倍,在计算calc(65535)
时慢1712倍
第一种算法的最坏情况似乎是54613=11010101012这样的数字。对于该值,第一种算法仅比第二种算法快16倍
在简单的递归算法中,calc(1000)
只需要调用50次calc
,甚至calc(54613)
也只需要5166次
此O(logn)算法速度更快:
def C(x):
a = 1
b = 0
# Loop invariant: we are going to return a*C(x) + b*C(x + 1).
while x >= 2:
if x % 2 == 0:
a += b
else:
b += a
x //= 2
return a + b
该算法的性能很容易评估,但其正确性却很差。;-) 您可以编写一个实际上是次线性(O(logn))的递归版本 关键是要注意,给定[n/2]和[n/2]+1的两个值,可以计算n和n+1的两个值 如果你把两个值看作一个元组T(n)=(F(n),F(n+1)),那么给定T([n/2]),你就可以计算T(n) 所以你的函数是这样的
Tuple F(int n) {
// Base cases:
Tuple result;
if (n is even) {
Tuple t = F(n/2);
result.First = t.First;
result.Second =t.First + t.Second;
return result;
}
if (n is odd) {
Tuple t = F((n-1)/2);
result.First = t.First + t.Second;
result.Second = t.Second;
return result;
}
}
这样,您只需要进行一次递归调用,并且由于每次调用的输入大小减半,因此它是递归的,并且是O(logn)
练习:使用此技巧给出斐波那契数的O(对数n)时间算法
提示:使用以下标识:
这是一个多么好的解释啊,我一定会读到:)我在这方面没有问题。@Nishant-希望我没有把数学搞砸。:-)@Paul Hankin-F(n)的值可能不大于n,但计算它的时间可能是,如果我们将每个递归调用收费为一个恒定的时间单位。这个递归公式(T(1)=1,T(2n)=T(n)+1,T(2n+1)=T(n)+T(n+1)+1)不容易被n限定。这里,你忘记了分配:3+c(5/2+1)为了证明递归版本是O(n),可能更容易限定递归的深度。这个深度是
第二句(“关键…”)不清楚/不完整。您的解决方案还需要这样一个事实,即您可以从n和n+1计算2n+2。def calc(n):如果……否则:返回未嵌套的计算(n/2)+calc(n/2+1)
,只需重复。尝试
T(n) <= T(n / 2) + T(n / 2 + 1) + 1
<= 1 + max{c(n / 2 + 1) + d, 1} + 1
<= 2 + max{c(n / 2 + 1) + d, 1}
<= 3 + c(n / 2 + 1) + d
3 + c(n / 2 + 1) + d <= cn + d
3 + c(n / 2 + 1) <= cn
3 + c(5 / 2 + 1) <= 5c
3 + 5c/2 + c <= 5c
3 + 7c/2 <= 5c
4 <= 3c / 2
8 / 3 <= c
T(n) <= T(n / 2) + T(n / 2 + 1) + 1
<= c(n / 2) + d + c(n / 2 + 1) + d + 1
<= cn / 2 + cn / 2 + c + 2d + 1
= cn + c + 2d + 1
cn + c + 2d + 1 <= cn + d
c + 2d + 1 <= d
c + d + 1 <= 0
T(n) <= max{8n/3 - 11/3, 1}
def C(x):
a = 1
b = 0
# Loop invariant: we are going to return a*C(x) + b*C(x + 1).
while x >= 2:
if x % 2 == 0:
a += b
else:
b += a
x //= 2
return a + b
Tuple F(int n) {
// Base cases:
Tuple result;
if (n is even) {
Tuple t = F(n/2);
result.First = t.First;
result.Second =t.First + t.Second;
return result;
}
if (n is odd) {
Tuple t = F((n-1)/2);
result.First = t.First + t.Second;
result.Second = t.Second;
return result;
}
}