【问题标题】:Finding Time and Space Complexity Of Recursive Functions查找递归函数的时间和空间复杂度
【发布时间】:2018-07-23 14:07:57
【问题描述】:

我在分析递归函数的时间和空间复杂性时磕磕绊绊:

考虑:

def power(a, n):
    if n==0:
        return 1
    else:
        return a*power(a, n-1)

当找到这个的时间复杂度时:我认为T(n) = c + T(n-1) 其中 c 是乘法的常数成本。

这可能会导致:c*n 成本,即线性成本 O(n)。但是递归的成本通常是指数级的。

另外,考虑这个函数:

def power(a,n):
    if n==0:
        return 1
    if n%2 ==0:
        return power(a*a, n//2)
    else:
        return a*power(a*a, n//2)

上述函数将一直持续到:T(n) = c + T(n/2),这意味着成本将是 c*log(n) 表示 log(n) 复杂度。

如果分析正确,那么递归看起来和迭代算法一样快,那么开销从何而来,是否有任何指数递归算法?

【问题讨论】:

  • 您可以将函数的顺序与它在实践中的运行速度(在小型数据集上)分开 - 一个简单的幂函数,迭代完成,比递归函数的开销要小得多,你在哪里设置每次通过一个新的堆栈框架和分支。正如您的分析所示,递归函数不一定是指数的。但是,它们往往在诸如 tree-walks 之类的事情上实际上很有用,它们会不可预测地分叉,在这种情况下,它们是指数级的(但更容易实现,并且与非递归函数一样好。)

标签: python algorithm recursion data-structures


【解决方案1】:

递归的复杂性是指数级的,这是不正确的。事实上,有一个定理,每个递归算法都有一个迭代类似物,反之亦然(可能使用额外的内存)。有关如何执行此操作的说明,请参见 here 例如。还可以查看维基百科中比较 recursion and iteration 的部分。

当递归函数在其某些流程中多次调用自身时,您可能会遇到指数复杂度,就像斐波那契数的著名示例一样:

def fib(n):
   if n < 2:
       return 1
   return fib(n - 1) + fib(n - 2)

但这并不意味着没有更快的递归实现。例如使用memoization,您可以将其归结为线性复杂度。

仍然递归实现确实有点慢,因为堆栈帧应该在进行递归调用时存储,并且在返回值时应该恢复。

【讨论】:

  • 你能陈述定理或名称/链接吗..以及如何通过分析表明上述算法具有指数复杂性?谢谢!!
  • 我添加了一个指向建设性证明的链接 - 进行转换的示例算法
  • @AndyMarkman 至于说明为什么上述算法具有指数复杂性,我更愿意将这一点留给您。从您的问题来看,您似乎处理得很好,而且您的两个估计都是正确的
  • 谢谢,我会尝试:T(n) = T(n-1) + T(n-2) 和 T(n-1) = T(n-2) + T(n -3) 和 T(n-2) = T(n-3) + T(n-4) => 对于 n 的每个值都有两个函数调用...然后,它看起来像:有 n 个级别并且在每个级别都有分支:没有。分支数 = 函数调用 = 2*2 * 2 n 次 => 2^n。我在想为什么不是:2 + 2 + 2 + 2...但是为此必须停止新函数调用...
  • 好的开始。还有一点需要注意的是,您会多次计算某些值 - 例如 T(n - 1) 和 T(n-2) 都依赖于T(n-3)。你能估计每个参数调用函数的次数吗?
猜你喜欢
  • 2019-04-21
  • 2018-02-10
  • 2019-03-02
  • 2017-09-04
  • 1970-01-01
  • 1970-01-01
  • 2018-05-29
  • 2018-08-18
相关资源
最近更新 更多