递归函数重复工作

时间:2011-10-28 11:07:51

标签: algorithm

某些递归调用有重复的工作。例如,在以下情况中,正在运行

T(n) = (sum from i to zero to (n-1) T(i) ) + n  

with T(0)=1。每个大小的一个(直接)递归调用从0到n -1, 加上O(n)额外的工作。

求解T(n),我们发现它呈指数增长。

递归调用上面生成什么样的树,这与分割和征服树一样吗?

谢谢!

1 个答案:

答案 0 :(得分:1)

我将尝试为此提供一些答案...措辞很差,但也许你可以接受这一点,并用我的理解来改进你的意思。

假设您正在询问计算T(n)的函数,以递归方式实现

  T(n)
  1. r := 0
  2. for i := 0 to n-1 do
  3.    r := r + T(i)
  4. r := r + n
  5. return r

这个递归的树看起来像这样......

      _______________________T(n)_____________________
     /       /          /            \                \
  T(0)    T(1)       T(2)            T(3)      ...    T(n-1)
           |         / \          /   |   \              |
          T(0)    T(0) T(1)     T(0) T(1) T(2) ...      ...
                       ...           ...  ....

树与用于评估Fibonacci序列的递归树非常相似;实际上,如果将总和限制在[n-2,n-1]而不是[0,n-1]之间,则会获得相同的树。要找到这个的运行时间,因为函数的非递归部分是O(1),我们只需要计算进行了多少次递归调用。

T(n)将进行n次递归调用,T(0),T(1),...,T(n-1)。作为调用T(n)的结果,T(n-1)将仅被调用一次; T(n-2)将被调用两次(一次作为T(n)的结果,再次作为T(n-1)的结果)。作为T(n)的结果,T(n-3)将被调用一次,作为T(n-1)的结果将被调用一次,并且对于T(n-2)的两次调用将被调用两次,共有4个电话。我们现在可以看到,由于T(n),T(nk)被称为2 ^(k-1)次;因此,如果我们将1和n之间的每个k的调用数相加,我们得到2 ^ n - 1 ......对吗?所以我们得到O(2 ^ n)函数的时间复杂度......就像天真的斐波纳契一样。

为了获得函数返回值的增长率,我们可以将函数本身看作是其他一些代码的递归关系。在这种情况下,我们可以开始列出几个术语......

  T(0) = c
  T(1) = c + 1
  T(2) = c + (c +1) + 2 = 2c + 1+2
  T(3) = c + (c + 1) + (2c + 1+2) + 3 = (4c +1+1+2+3)
  T(4) = c + (c + 1) + (2c + 1+2) + (4c + 1+1+2+3) + 4 = 8c +1+1+1+1+2+2+3+4
  ...
  T(n) = c*2^(n-1) + 1*2^(n-2) + 2*2^(n-3) + 3*2^(n-4) + ... + (n-1)*2^0 + n
       = c*2^(n-1) + sum(i*2^(n-i-1) for i := 1 to n-1) + n

我们可以稍微简化这个总结......

  T(n) = c*2^(n-1) * 2^(n-1)*sum(i*2^(-i) for i := 1 to n-1) + n

因此,为函数的增长顺序获得闭合形式的解决方案的问题被简化为找到求和的增长顺序i * 2 ^( - i)。我的钱说你可以比增长订单做得更好......这有一个封闭的形式吗?无论如何,这应该足以帮助,如果不是你的问题的完整答案。