iteration
とrecursion
の違いは何ですか?なぜ/いつの方が良いですか:
while (true) {
// Iterating
}
そして
private void recursion() {
if (true)
recursion(); // Recursing
return;
}
単純なループで簡単に実行できますが、多くのrecursive
実装があります。
再帰と同じアルゴリズムの反復バージョンには、主に2つの違いがあります。
まず第一に、反復アルゴリズムよりも再帰アルゴリズムを理解する方がよい場合があります(少なくとも経験豊富なプログラマーの場合)。したがって、表現力が向上し、場合によっては可読性が向上します(他の場合はまったく逆になる場合もあります) )
プログラミング言語ではExpresivityが非常に重要であり、20行ではなく5行で同じコードを記述できることは非常に重要です。
欠点は、コードのパフォーマンスが低下することです。再帰関数は、関数レコードをメモリ内に保持し、パラメータを渡し値を返すために呼び出されるメモリアドレスから別のメモリアドレスにジャンプする必要があります。そのため、パフォーマンスが非常に悪くなります。
合計:
反復アルゴリズム=高速なパフォーマンスですが、書きにくい(読みにくい場合もあります)
再帰的アルゴリズム=書き込みは高速ですが、パフォーマンスが悪い(時々わかりやすい)
次の例をご覧ください。
public static long fib(long n) {
if (n <= 1) return n;
else return fib(n-1) + fib(n-2);
}
対
if ((n == 1) || (n == 2)) {
return 1;
} else {
long prev = 1, current = 1, next = 0;
for (long i = 3; i <= n; i++) {
next = prev + current;
prev = current;
current = next;
}
return next;
}
ソース:
http://www.csd.uwo.ca/Courses/CS1027a/code/FibonacciDemo.Java
再帰と反復の主な違いは、メモリ使用量です。
再帰呼び出しごとに、スタックフレーム上のスペースが必要になるため、メモリのオーバーヘッドが発生します。
例を挙げましょう。あるケースでは、再帰関数のベースケースを書くのを忘れて、結果として無限の再帰呼び出しを行い、他のケースでは無限ループを書いたと想像してください。
すべての再帰関数は新しいメモリ空間を割り当てるため、最初のコードではスタックオーバーフロー例外が発生しますが、2番目のケースでは永久に実行され続けます。
そのため、再帰を使用するよりも、反復コードをより理解しやすくする方が適切です。
それらは同じことをする異なる方法です。すべての再帰的な実装は、(または複数の)ループで行うことができ、逆も同様です。それの背後にあるロジック、それについて考える方法についてです。階乗は、最良の例ではありませんが、n * (n-1)!
であるため、再帰的に使用するのが理にかなっています。
理論的には、反復と再帰をいつでも交換できます。ただし、少なくともC/C++/C#/ Javaの場合、コンパイラは、特にループの数がわからない場合に、ソリューションをよりエレガントにするいくつかのサポートを提供します。
最良の例は、フォルダー内のすべてのファイルとその子孫を一覧表示することです。サブフォルダーを含むサブフォルダーが複数ある場合、通常、反復モードでは、分析する必要のあるすべてのフォルダーを保存するためのスタックが必要です。再帰的なアプローチの場合、スタックは既にコンパイラーによって提供されており、ソリューションはよりエレガントです。
再帰と反復は、解決策を考えるための異なる方法です。完全な範囲の違いを詳細に説明することは困難です。サンプルコードでは、違いを示しています。再帰関数はそれ自体を呼び出す関数であり、反復関数はコードのブロックをループする関数です。それらをよりよく理解するのに役立ついくつかの記事を次に示します。 再帰wiki
それらは、さまざまな問題を解決するために交換可能に使用できます。本質的に、再帰関数を繰り返し記述したり、その逆も可能です。
反復により、プログラムのパフォーマンスが向上する場合があります。一方、再帰はより直感的でエレガントな結果をもたらす可能性があります。どちらをお好みに選択できます!
再帰関数は条件が満たされるまで自分自身を呼び出すプロセスを実行しますが、反復は特定の条件が満たされるまでコードのセクションを繰り返すためにループ制御構造(たとえば、while、do while、for)を使用します。
再帰的な例:
int rec_func(int u, int k) {
if (k == 0)
return u;
return rec_func(u * k, k - 1);
}
反復の例:
int ite_func(int u, int k) {
while (k != 0) {
u = u * k;
k = k - 1;
}
return u;
}
それらの間の唯一の本当の違いIMOはコンパイルの違いです。