2010-12-12 13 views
9

再帰呼び出しが容易に実装されないか望まれない設定で、既存のコードを書き直しています。 (と知っている必要がある場合、Fortran 77で)私は必要な呼び出しを追跡するためにスタックを最初から作ることを考えましたが、これはクルージングのようです。再帰は深くない。 (私は、Fortran 77が動的配列のサイジングをサポートしているとは確信していません)再帰呼び出しを使用せずに再帰関数を書き換える

明らかに再帰的な関数をどのようにしてスタックにスペースを浪費することなく非再帰的に書き直す方法に関する他の提案はありますか?

多くのおかげで、 旧MCST

+2

分岐しない場合は、通常、単純なループに書き換えることができます。分岐する場合、通常はスタックが必要です。 – CodesInChaos

+1

@CodeInChaos:分岐しない再帰関数は、定義によって決して戻りません。 –

+0

私は単語の枝を誤用していると思います。私はそれ自身を複数回呼び出すことを意味するので、コールのグラフはブランチを持つツリーになります。それは私の経験であり、必ずしも真実ではありません。 – CodesInChaos

答えて

14

あなたのコードは末尾再帰を(つまり、関数が直接、他の処理をすることなく、すべての再帰呼び出しの結果を返す、である)スタックせずに命令的機能を書き換えることが可能です使用している場合:

function dosomething(a,b,c,d) 
{ 
    // manipulate a,b,c,d 
    if (condition) 
    return dosomething(a,b,c,d) 
    else 
    return something; 
} 

の中へ:

function dosomething(a,b,c,d) 
{ 
    while (true) 
    { 
    // manipulate a,b,c,d 
    if (condition) continue; 
    else return something; 
    } 
} 

テール再帰がない場合、スタック(または同様の中間記憶域)を使用することが唯一の解決策です。

+0

これは私が考えていたものに似ていますが、言葉に入れられませんでした。私の場合、私は、セットの他の要素との関係をテストする必要がある要素のデータセットを持っています。私はすべてのアイテムのデータ構造を渡すことができましたが、それぞれの処理が必要なので、スタックは不可避ですと思います。 –

+0

に依存します。コードが主に「すべてのペア(a、b)に対してP(a、b)が真であればF(a、b)を実行する」ならば、すべてのペアを反復してループすることができます。 –

2

ほとんどの再帰関数を簡単にスペース無駄にように、ループのように書き換えることができます - 多くの(すべてではない)の再帰的なアルゴリズムは、実際の種類に依存するため、機能に依存します(ただし、これらの場合でも通常ループバージョンが効率的です)。

+0

スタックにスペースを必要としない再帰関数を見せてもらえますか?その議論でさえ? –

+1

@Nikita Rybak:インラインテール再帰関数;) –

+0

@Victorええ、それは書き直された形です。 Ofirは、スタックメモリを必要としない再帰関数があると主張しています。だから私は好奇心が強い。 –

3

ループは、フィボナッチ関数であるように書くことができる古典的な再帰関数:

function fib(n) 
{ 
    // valid for n >= 0 
    if (n < 2) 
     return n; 
    else 
     return fib(n-1) + fib(n-2); 
} 

しかし、メモ化せず、これはO(N)、スタック領域とO(EXP^N)操作を要します。

はそれを書き換えることができます。

function fib(n) 
{ 
    if (n < 2) 
     return n; 
    var a = 0, b = 1; 
    while (n > 1) 
    { 
     var tmp = a; 
     a = b; 
     b = b + tmp; 
     n = n - 1; 
    } 
    return b; 
} 

しかし、この機能は、それが自動プロセスに一般化することができるかどうかわからない、どのように機能するかについての知識を必要とします。