Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/351.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 嵌套递归是可能的还是应该避免递归?_Python_Algorithm_Recursion_Big O - Fatal编程技术网

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;
    } 
}