再帰-「分割して征服する」か「コードを再利用する」か


11

再帰 -誰もが知っているように-これらの問題の1つです-あなたの頭を包むことは、プログラミングの旅で「マイルストーン」を達成するような気がします。

しかし、実際の問題で実際に使用する場合は、再帰のメカニズムを知るだけでは十分ではありません。再帰が最も適切な解決策である問題の性質も理解する必要があります。

私の質問はこれです...

  • 再帰の解決を要求する「問題パターン」とは何ですか
  • 再帰は「分割統治」戦略の形式、または「コード再利用」の形式です-または、それ自体が設計パターンです
  • 再帰が即座の解決策として頭に浮かぶ現実世界の問題の例を教えてください

-更新-

多くの答えは、「本当の問題」をツリー探索や階乗などと呼んでいます。「本当の本当の問題」を好むでしょう。例を挙げましょう...

テキストの大規模なチャック(のリンクリストとして約30 MBのテキストstructs)があり、全文検索のためにそのインデックスを作成する必要がありました。インデックス全体をメモリに保持し、10分ごとにテキストのインデックスを再作成する必要がありました。

10分ごとに、テキスト全体(2つのリンクリスト、1行ずつ)と新しく生成されたテキストチャンクを比較し、変更された行を確認し、その行のみを再インデックスしますテキスト全体のインデックスを再作成する必要がなくなりました。覚えておいてください-2つの30 MBのリンクリスト間の差分ポイントを見つける必要がありました。

私の同僚の一人は、HEAVY再帰を使用して行を比較する素晴らしいプログラムを思い付きました-そして、チャックが配列内で異なる位置を収集します-はいやった

要点は、再帰を頻繁に使用することで、この問題をスマートに解決できることをどのように確認できるのでしょうか?


最近、ほとんどのコンピューターにGBのRAMとTBのハードドライブ領域がある30 MBは本当に大きいですか?
JBキング

30 MBはそれほど大きくないかもしれませんが、テキストが詰め込まれたデータ構造の種類を考慮すると、実際にはPROCESSへのテキストの大きなチャックであり、DIFFです。
ツリーコーダー

3
「フォルダ構造をたどる」ことは実際には十分ではありませんか?そして、あなたの例では、再帰がここで直感的ではないはずであり、なぜその使用が特に注目されるべきであるのか、完全に見当たりません。あなたの同僚は、他のアルゴリズムと同じように、再帰的なアルゴリズムを設計しました。また、Hoareがソート問題を再帰的に解決するアイデアをどのように得たのかを尋ねることもできます。
コンラッドルドルフ

2
「コードの再利用」を「同じ一連の操作を不定の回数実行する」という意味でしたと思いますか?他の場所で使用する汎用コードを作成するという意味での「コードの再利用」とは対照的です。
アンディハント

4
しかし、ツリートラバーサルは「実際の実際の問題」であり、多くの人がほぼ毎日直面しています。
ファルコン

回答:


16
  • 再帰の解決を要求する「問題パターン」とは何ですか

再帰を使用するための問題パターンのようなものがあるとは言いません。再帰を使用して実装できるすべての関数は、スタックをプッシュおよびポップすることにより、繰り返し実装することもできます。

それは表現の問題であり、パフォーマンスの問題でもあります。多くの場合、反復アルゴリズムはパフォーマンスが向上しており、最適化が容易です。ただし、再帰アルゴリズムはより明確な式の恩恵を受けるため、多くの場合、読みやすく、理解しやすく、実装しやすいです。

無限のリストなど、再帰なしでは表現できないものもあります。いわゆる関数型言語は、自然な表現方法であるため、再帰に大きく依存しています。「再帰プログラミングとは、関数型プログラミングを正しく行うこと」です。

  • 再帰は「分割統治」戦略の形式、または「コード再利用」の形式です-または、それ自体が設計パターンです

デザインパターンとは呼びません。それは表現の問題です。再帰式は、単により強力で表現力豊かであるため、より優れた、よりクリーンなコードになる場合があります。

  • 再帰が即座の解決策として頭に浮かぶ現実世界の問題の例を教えてください

ツリーをトラバースする必要があるものはすべて、再帰アルゴリズムによって適切に表現されます。


7
「再帰で実装できるすべての関数は、スタックをプッシュおよびポップすることにより、繰り返し実装することもできます。」結局のところ、スタックベースのメモリを利用する言語では、再帰を使用するときに、すでにスタックに対して関数データをプッシュしたりポップしたりしています。
JAB

マシンで言語をコンパイルまたは解釈する場合のみ;-)また、非常に高い観点からは、式と言語はマシンとハードウェアおよびOSから完全に独立しているため、必ずしもスタックはありません。
ファルコン

ああ、はい、あなたは絶対に正しいです。「スタックベースのメモリを利用する言語/言語コンパイラの実装」と言っていたはずです。
JAB

一般的に言えば、あなたも正しい。私はちょっとした見たくありませんでした。
ファルコン

2
無限リスト、再帰なしで、少なくとも再帰的な実装なしで表現できます。Pythonジェネレーターは、Pythonがアイデアを借用しているように見えるIconのジェネレーターと同様に、それを行うことができます。確かではありませんが、F#でこのトリックができると思います。基本的に、ジェネレーターは、レイジーリストの実装に適したコルーチン(協調マルチタスクなど)の特殊なケースです。ジェネレーターが結果を「譲る」たびに、呼び出し側は制御を取り戻し、次の結果が要求されるまでジェネレーターはアイドル状態のままです。
Steve314

8

再帰は「分割統治」戦略の形式、または「コード再利用」の形式です-または、それ自体が設計パターンです

どちらでもない。分割統治で再帰を使用します。しかし、再帰は必ずしも問題を2つ(またはそれ以上)の部分に分割し、それぞれを対称的に解決することを意味するため、分割と分割は必ずしも必要ではありません。再帰では、これを行いません。

コードの再利用は完全に無関係であり、設計パターンははるかに高いレベルで機能します。たとえば、分割と征服(再帰よりも高レベルのパターン)でさえ、デザインパターンとは見なされません。むしろ、アルゴリズムパターンです。

再帰が即座の解決策として頭に浮かぶ現実世界の問題の例を教えてください

ツリートラバーサル。または、より一般的には、グラフトラバーサル。これには、フォルダー構造の走査が含まれます。

もちろん、分割統治法または動的プログラミングを使用するものはすべて、再帰の観点で自然に表現されているためです。


動的プログラミングは必ずしも自然に再帰として表現されるとは限りません。実際、動的プログラミングは厳密に表形式のアプローチを指します-メモ化を除きます。これについては意見が異なるようですが、「動的プログラミング」の「プログラミング」は実際には数学用語であり、表形式のアプローチ(MITオープンソースウェアアルゴリズムコースから選んだ雑学の一部)を指します。厳密に言えば、動的プログラミングでは、単純なループとして最も簡単に表現できるものを使用して、最適な部分構造を活用します。メモ化は再帰を暗示する可能性がはるかに高いですが、必ずしもそうではありません。
Steve314

1
@ Steve314 DPの実際の実装(コンピュータープログラムまたは手動)が再帰をほとんど使用しないことに同意します。しかし、アイデアは本質的に再帰関係に基づいています-これは単なる再帰的な式です!–およびベースケース。
コンラッドルドルフ

「最適な部分構造」(最適な解には最適な部分解がある)は再帰的なアイデアであることに同意します。これは数学/コンピューターサイエンスの再帰の考え方であり、実装に直接関係するものではありませんが、コンピューターサイエンスにおける再帰の役割は重要なポイントです。コンピューターサイエンスの重要なツールであるアルゴリズムはほとんどありません(おそらくデザインパターンはありません)。ほとんどは、他の学習に使用するツールではなく、純粋に研究対象です。
Steve314

4
what are the "problem patterns" that call for the solution of recursion

フラクタルの自己相似性から派生した、自己平等または自己同一性(またはそれが呼ばれている)は、再帰の典型的な問題パターンであると言えます。つまり、問題は、メインの問題とまったく同じ構造を持つサブ問題に分割できます。

前述のツリートラバーサルでは、各サブツリーはメインツリーと同様にそれ自体が完全なツリーであり、メインツリーは別のツリー内のサブツリーにすることができます。

それで、あなたの同僚はあなたのインデックス作成問題の自己平等性を発見したと思います。または、彼は反対に回り、問題を自己同等の表現に変えました。


1
「問題は、主な問題とまったく同じ構造を持つサブ問題に分割できる」
treecoder

+1と言い換え:問題の解決策は子層に適用されます。私の実世界の例は、「バッチ」に寄与するクレジットカードの請求を見つけることです。会計ソフトウェアには、当座預金口座への個別の請求と一括入金が含まれます。私の場合、stackoverflowはそれほど鋭くないので、ここで質問になるかもしれません。stackoverflow.com/questions/14719806
クリスK

3

命令型ループを関数に変換しようとすると、再帰は簡単に理解できます。とにかく、すべての質問に答えてみましょう。

再帰の解決を要求する「問題パターン」とは何ですか

ツリーのような構造またはアルゴリズムがある場合は、再帰が必要です。命令コードがスタックを処理する場合、再帰が必要になります。アルゴリズムの特定のステップが前のステップに依存している場合(ループを考える)、再帰が必要です。ここで必要なのは、使用できるように解釈されることです。

再帰は「分割統治」戦略の形式、または「コード再利用」の形式です-または、それ自体が設計パターンです

なし。分割統治では再帰を使用しますが、スタックで実装できます。コードの再利用とは、別のものを指します。設計パターンは、単純な再帰よりも複雑です。

再帰が即座の解決策として頭に浮かぶ現実世界の問題の例を教えてください

構文解析およびツリー構造を扱うすべて。暗黙のツリー構造ですら。


3

簡単にするためにそれを単純化する方法があれば、それが再帰が機能する手がかりになる可能性があります。それぞれ、ソートのマージバイナリ検索などの再帰的なソリューションが存在する場合、ソートと検索の例を使用できます。

心に留めておくべきことは、階乗のような再帰でいくつかの問題をどのようにうまく解決できないかです。

再帰を使用する実際の例として、本の棚から本を検索することは、再帰的に非常に簡単に行うことができます。私は本を​​見て、それが私が望むものでないならば、私は次のものに移ります。本を見つけるか、行の終わりに到達すると停止します。本を確認し、次の本に移動するループは、再帰的に実行できます。おそらくこれは実例ではあまりにも現実的です。


2

再帰の解決を要求する「問題パターン」とは何ですか

非常に一般的な言葉で言えば、f(x)= f(g(x))の問題を解決するときに再帰が必要です。無限再帰で大丈夫でない限り、g(x)xに評価されるべきではありません。

再帰は「分割統治」戦略の形式、または「コード再利用」の形式です-または、それ自体が設計パターンです

上記のどれでもない。これは、入力のバリエーションに基づいて、同じことを繰り返し行う方法にすぎません。その概念は、設計パターン、コードの再利用、さらにはコンピューターよりもはるかに長いものでした。

再帰が即座の解決策として頭に浮かぶ現実世界の問題の例を教えてください

階乗、フィボナッチ数列、ツリートラバーサル、その他の多くの問題は、再利用で解決できます。関数自体を呼び出すという意味での再帰は、必ずしもこれらの種類のものを実装する最良の方法ではありません。同じ効果を達成する他の方法(スタックとループなど)があります。


-1

再帰アルゴリズムを作成するとき、通常、問題の再帰定義をコードに変換します。そうすれば、実行方法を知る必要すらありません。

それが関数型プログラミングで起こることです。実際、どのようにではなく(定義)を指定します。つまり、ベースを定義してから、サブ問題の用語で問題を定義します。

たとえば、Factorialアルゴリズムを考えます

  • ベースを定義します:Factorial(1)= 1;
  • 階乗nの定義:階乗(n)= n *階乗(n-1);

次に、問題が発生した場合、再帰的に定義できるかどうか、再帰的に定義できる場合はほとんど解決できていると考えてください。

ただし、再帰関数は再帰定義であってはなりません。ベースを定義し、メインの問題の解決策をサブ問題の解決策(定義)に関連付ける(定義する)ことができます。ただし、この関係には手順が必要な場合があります。

例としてはMergeSortmerge配列全体を並べ替える定義またはソリューションをサブ配列の並べ替えに関連付けるための必須の手順があります。

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