すべての再帰関数を反復でコーディングできますか?[閉まっている]


10

再帰の利点は何ですか?

一部のプログラミング言語は末尾再帰を最適化できますが、一般的な用語では、再帰は通常のループよりも多くのリソースを消費します。

いくつかの再帰関数の反復バージョンを持つことは可能ですか?



回答:


10

はい、再帰関数を反復としてコーディングできます。基本的に、手動で情報を維持する必要があります。そうしないと、コンパイラーによって生成されたコードを呼び出すメソッドによって処理されていました。

つまり、各エントリが渡されたパラメータとすべてのローカル変数を含む構造であるスタックが必要です。常にスタックの一番上のエントリで作業します。自分を呼び出す必要がある場合は、新しいエントリを作成してスタックの一番上に置きます。完了したら、スタックの最上位のエントリを取得し、下のエントリを公開し、以前の最上位のエントリを使用して戻り値を抽出し、それに応じて新しい最上位のエントリを更新します。

これが通常マシンコードでどのように実装されているかを確認するために、コンパイラの本を研究することをお勧めします。


わかった。では、再帰にはどのような利点がありますか?シンプルさ?
OscarRyz 2010

2
@OscarRyz:はい、そしてよりエレガントです。
マイケルK

@OscarRyz、私が説明した方法再帰です。これは、ネイティブのCPU命令では行われません。手動で実行すると、並列化など、ネイティブの命令に適切にマッピングされないことを実行できます。

15

多くの場合、再帰は反復よりも物事をより自然に見る方法です。たとえば、バイナリツリーの順序トラバーサルを考えてみ inorder(left); process(); inorder(right);ます。これは、スタックを明示的に維持するよりもはるかに簡単です。

深く掘り下げない限り(スタックを吹き飛ばして)、リソース使用量の違いは通常、取るに足らないものです。一般的には心配しないでください。例外はありますが、通常、単純なコードは手動で最適化されたコードよりも優れています。権利は通常、高速よりも優れています。

再帰アルゴリズムは反復アルゴリズムとして表現できますが、明示的にスタックを保持する必要がある場合があります(暗黙的に処理される呼び出しスタックに対応)。結局のところ、再帰関数をコンパイルすると、スタックの操作と関数のループ処理に依存するものが得られ、それが反復的です。

末尾再帰関数はループに簡単に変換でき、スタックは必要ありませんが、それは特殊なケースです。


8
私は右が常に速いよりも優れていると思います。間違ったことをすぐに実行するコードは、だれにとってもあまり良くありません。
メイソンウィーラー、

1
しかし、もしあなたがその間違ったことを本当に迅速に行うことができるとしたら?
RationalGeek

1
@jkohlhepp-問題があればすぐに解決できます。答えは0です。
名前を考える-自己への注意

2
明示的なスタックではなく再帰を使用する方が効率的です。ヒープの割り当て、メモリの断片化の可能性、および局所性の問題の可能性を回避できます。ただし、「正しい方が通常は高速より優れています」では、ソフトウェアが処理する必要がある場合のスタックオーバーフローは、コードが壊れていることを意味します。通常、問題のケースはかなり簡単に見つけることができます-(合理的に)バランスの取れたツリーでの再帰は問題ありませんが、非常にアンバランスなツリーでの再帰、またはリンクされたリストでの再帰は、Cなどの言語の深刻なバグになる可能性があります。 、それは単純なテストに耐えることができ、実際にデプロイされた場合にのみクラッシュします。
Steve314

1
メイソンが何を意味するのか理解していて、ただ冗談を言っているだけだと思います。もちろん、遅い正しいプログラムは速い正しくないプログラムよりも有用です。
ジョルジオ

4

再帰の利点は何ですか?

ハノイの塔の問題を繰り返し解決してみてください。あきらめたら、反復的な解決策を見て、それを再帰的な解決策と比較してください。どちらが簡単ですか?

いくつかの再帰関数の反復バージョンを持つことは可能ですか?

はい、原則として。ただし、ツリートラバーサルなどの非常に一般的なタスクを含む多くの問題では、再帰的ソリューションは反復的ソリューションよりもはるかに単純でエレガントです。


3

再帰の利点は何ですか?

シンプルさ。もちろん、末尾呼び出しの最適化がなければ、より多くのリソース(スタック)が必要になりますが、たとえば、deltree再帰なしでJavaにどのように実装しますか?ひねりは、delete()ディレクトリが空の場合にのみディレクトリを削除できることです。ここに再帰があります:

deltree(File fileOrDirectory) {
    if (fileOrDirectory.isDirectory()) {
        for (File subFileOrDirectory : fileOrDirectory.listFiles()) {
            deltree(subFileOrDirectory);
        }
    }
    fileOrDirectory.delete();
}

1
他の回答で述べたように、スタック。
Nicole

はい、しかしそれはどれほど簡単ですか?-)
Joonas Pulakka

ああ、再帰は間違いなく優れています。それは不可能だと言っていたと思いました。
ニコール

0

再帰は、プログラマーが生きなければならないツールの1つだと思います。再帰を使用すると、アルゴリズムを「考え」、考えたとおりにアルゴリズムを解くことができます。しかし、私はあなたに警告しなければなりません、私が言うべきいくつかのことに関して、誰もがかなり再帰がいかに素晴らしく、コードにどれほど単純さがもたらすかについて話している:

  1. まず、アルゴリズムの「再帰的な方法」を考えるのは簡単ではありません。階乗(n!)のような関数やハノイの塔のようなものを構築することは氷山の一角にすぎず、底に到達するには長い時間がかかります。
  2. 再帰がコードに単純さをもたらすとは思わないでください。反復的な方法は醜くて厄介ですが、費用対効果が高いです(フィボナッチ問題の再帰的解決策を調べてください)。

それらを念頭に置いて、再帰を学びましょう!面白くて複雑で、脳を壊すでしょう!

がんばって!

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.