引数をスタックにプッシュして関数呼び出しを置き換え、スタックからポップして戻り、再帰を排除しました。
編集:再帰的なアルゴリズムが一定の間隔で実行できる場合
を「スタックを使用すると、スペースコストを削減しない」に応答して、それは末尾再帰的に書き込むことができます。 tail-recursive形式で記述されていれば、適切なコンパイラがスタックを折りたたむことができます。しかし、これは、 "明示的なスタックプッシュへの関数呼び出しの変換"メソッドも一定のスペースを取ることを意味します。一例として、階乗をとることができます。
階乗:
def fact_rec(n):
' Textbook Factorial function '
if n < 2: return 1
else: return n * f(n-1)
def f(n, product=1):
' Tail-recursive factorial function '
if n < 2: return product
else: return f(n-1, product*n)
def f(n):
' explicit stack -- otherwise same as tail-recursive function '
stack, product = [n], 1
while len(stack):
n = stack.pop()
if n < 2: pass
else:
stack.append(n-1)
product *= n
return product
stack.pop()は、ループ内で)(stack.appendに追従するので、スタックがその中に複数の項目を有することがない、そしてそれは、一定の空間を満たします要件。長さ1のスタックの代わりに一時変数を使用すると想像するなら、それはあなたの標準反復法のアルゴリズムになります。
もちろん、末尾再帰形式では書き込めない再帰関数があります。何らかのスタックを使って反復フォーマットに変換することはできますが、スペースが複雑であることが保証されていれば驚くでしょう。
あなたは再帰的な呼び出しに依存します。スタックを実装することによってすべての再帰関数を非再帰関数に変換することができます。 – yairchu
はい、それはここで詳しく説明されています:http://stackoverflow.com/questions/1094679/ –
@Marc Gravell:それは絶対に素晴らしいです! –