再帰関数は作業を複製する

一部の再帰呼び出しには重複した作業があります。例えば、以下の場合には、

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

T(0)= 1 。0からn -1までの各サイズの1つの(直接の)再帰呼び出しです。 O(n)追加作業。

T(n)を解くと、指数関数的に増加することがわかります。

再帰呼び出しの上にどのような種類のツリーが生成されますか?分割と征服のツリーと同じですか?

ありがとう!

1
それは反復関係です、それはすべての呼び出しを生成しません...
追加された 著者 Karoly Horvath,
イエップ、DPまたはメモ
追加された 著者 Karoly Horvath,
あなたが何を求めているのか分かりません。上記の関数は、数学的関数の一種である反復関係です。数学には「再帰的呼び出し」はありません。あなたは素朴な方法でその関数を実装しようとすると再帰呼び出しを受け取ります(より良い方法があるかもしれません)。また、重複した作業についても言及しています。はい、純粋な実装では重複した作業があります。この作業は、この関数を計算するために再帰を使用しないことで簡単に削除できます(動的プログラミングなど)。
追加された 著者 LiKao,

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) ...      ...
                       ...           ...  ....

木はフィボナッチ数列の評価のために得られる再帰木と非常に似ています。実際には、[0、n-1]の代わりに[n-2、n-1]の間に集計を制限すれば同じツリーが得られます。この実行時間を見つけるには、関数の非再帰部分がO(1)なので、再帰呼び出しが何回行われたかを数えるだけで済みます。

T(n)はn個の再帰呼び出しT(0)、T(1)、...、T(n-1)を作る。 T(n)を呼び出した結果、T(n-1)は1回だけ呼び出されます。 T(n-2)は2回(T(n-1)の結果として1回、T(n-1)の結果として1回)呼び出される。 T(n-1)の結果として1回、T(n-2)への2回の呼び出しの結果として2回、合計4通。 T(n)は、T(n)の結果として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)の成長次数を求めることに還元される。私のお金は、あなたが成長秩序よりも良いことをすることができると言います...これには閉じた形がありますか?とにかく、あなたの質問に対する完全な答えではないにしても、これは助けてくれるはずです。

1
追加された