アルゴリズム | 再帰の深い理解、あなたは再帰を誤解しています

アルゴリズム | 再帰の深い理解、あなたは再帰を誤解しています

再帰は、プログラミングの本で説明するのが最も難しい部分である魔法のアルゴリズムです。これらの本では通常、階乗の再帰的な実装が示され、動作するが非常に遅く、スタック オーバーフローでクラッシュする可能性があるという警告が表示されます。懐疑的な人もいるが、再帰がアルゴリズムにおける強力なアイデアであるという事実には影響しない。

[[277071]]

古典的な再帰階乗を見てみましょう。

階乗.c

  1. #include <stdio.h>
  2.  
  3. int階乗( int n)
  4. {
  5. int前 = 0xdeadbeef;
  6.  
  7. (n == 0 || n == 1)の場合{
  8. 1 を返します
  9. }
  10.  
  11. 前 = 階乗(n-1);
  12. n * previousを返します
  13. }
  14.  
  15. int main( int argc)
  16. {
  17. int答え = 階乗(5);
  18. printf( "%d\n" , 回答);
  19. }

関数が自分自身を呼び出すという考え方は、最初は非常に不思議です。全体のプロセスを説明するために、次の図は、factorial(5)が呼び出され、n == 1の場合のスタックの構造を示しています。

factorial を呼び出すたびに、新しいスタック フレームが生成されます。これらのスタック フレームの作成と破棄により、再帰要素は反復部分よりも遅くなります。呼び出しが開始される前と戻る前にこれらのスタック フレームが蓄積されると、スタック領域が使い果たされ、プログラムがクラッシュする可能性があります。

しかし、こうした懸念は一般的に理論的なものである。たとえば、階乗スタック フレームはそれぞれ 16 バイトを占有します (これはスタックの配置やその他の要因によって異なる場合があります)。コンピュータで最新の x86 Linux カーネルを実行している場合、通常はデフォルトで 8 MB のスタック スペースがあるため、階乗 n は最大 512,000 を処理できます。これは非常に大きな数であり、表現するには 8,971,833 ビットを必要とするため、スタック スペースは問題になりません。小さな整数 (64 ビットであっても) は、スタック スペースがなくなる前に何万回もオーバーフローします。

CPU 使用率については後で説明しますが、今はビットやバイトから離れて、一般的な手法としての再帰について見てみましょう。私たちの階乗アルゴリズムは、整数 N、N-1、... 1 をスタックにプッシュし、それらを逆の順序で乗算することになります。プログラムの呼び出しスタックを使用してこれを行うための前提は、ヒープ上にスタックを割り当てて使用できることです。コール スタックには特別なプロパティがありますが、これは自由に使用できる別のデータ構造にすぎません。

コール スタックをデータ構造として見ると、別のことが理解できるようになります。つまり、すべての整数をそれ自体の前に追加し、それらをそれ自体で乗算することは、明らかに賢い考えではありません。 階乗を計算するには、反復プロセスを使用する方が合理的です。

伝統的な面接の質問に、迷路の中にネズミが置かれ、ネズミがチーズを見つけるのを手伝うというものがあります。ネズミは迷路の中で左または右に曲がることができると仮定します。この問題をどのようにモデル化して解決しますか?

人生におけるほとんどの問題と同様に、このげっ歯類の課題をグラフ、具体的にはノードが迷路内の位置を表すバイナリ ツリーに抽象化できます。次に、ネズミをできるだけ左に曲げ、行き止まりに達したら戻って右に曲がるようにします。次の図はマウスのパスを示しています。

各エッジ(線)は左または右に曲がることができ、マウスで選択できます。どちらかのターンがブロックされている場合、対応するエッジは存在しません。コール スタックを使用する場合でも、他のデータ構造を使用する場合でも、このプロセスは本質的に再帰的です。しかし、コールスタックの使用は非常に簡単です。

迷路.c

  1. #include <stdio.h>
  2. #include "maze.h"  
  3.  
  4. int探索(maze_t *ノード)
  5. {
  6. int見つかった = 0;
  7.  
  8. if (ノード == NULL ) {
  9. 0を返します
  10. }
  11.  
  12. if (node->hasCheese) {
  13. return 1; // チーズが見つかった
  14. }
  15.  
  16. 見つかった = explore(node-> left ) || explore(node-> right );
  17. 戻り値が見つかりました。
  18. }
  19.  
  20. int main( int argc)
  21. {
  22. int found = explore(&maze);
  23. }

maze.c:13 でチーズを見つけます。ここにスタックがあります。

ここで再帰を回避することは困難ですが、コール スタックを介して実行する必要があるわけではありません。たとえば、文字列 RRLL を使用してターンを追跡し、その文字列に基づいてマウスの次の動きを決定することができます。または、チーズ探しのステータスを記録するために他の変数を割り当てることもできます。再帰的な手順を実装していますが、独自のデータ構造を展開しています。

コールスタックがぴったり合うため、これはさらに複雑になる可能性があります。各スタック フレームには、現在のノードだけでなく、そのノードでの計算の状態も記録されます (この場合、左側のみを実行したか、右側を既に試したか)。しかし、私たちは溢れることを恐れて、良いものを諦めてしまうことがあります。それはとても愚かなことだと私は思います。

これまで見てきたように、スタックは大きく、スタック領域よりも先に他の制約が満たされることがよくあります。問題の大きさを確認し、安全に処理できるかどうかを確認することもできます。 CPU に対する恐怖は、主に、愚かな因子と、メモリのない信頼性の高い O(2n) 再帰フィボナッチという 2 つの広く見られる病理の例によって植え付けられます。これらは健全なスタック再帰アルゴリズムを表すものではありません。

実際には、スタック操作は高速です。データのオフセットは正確で、スタックはキャッシュ内にあり、コールド スタートは必要なく、ジョブを完了するための専用の命令があります。同時に、独自のヒープ割り当てデータ構造を使用すると、多くのオーバーヘッドが発生します。コールスタックの再帰よりも複雑でパフォーマンスの悪いものを書いている人がいるかもしれません。

最近の CPU は非常に優れており、通常はボトルネックにはなりません。多くの場合、シンプルさはパフォーマンスにつながります。

<<:  AIとIoTが現代の商取引と小売業を強化

>>:  顔認識のためのディープラーニングとオブジェクト検出のステップバイステップガイド

ブログ    
ブログ    
ブログ    
ブログ    

推薦する

「柯潔は2つの石を与えられた」が、それでもAIに負けた。プログラマーが知っておくべきトップ10のAIライブラリとフレームワークはこちら

[51CTO.comより引用] 遅かれ早かれ、この日はやって来る。イ・セドルがアルファ碁に1対4で負...

4Dミリ波レーダーSLAMソリューション研究

この記事は、Heart of Autonomous Driving の公開アカウントから許可を得て転...

...

1日で6つの賞を獲得! PATEOの自動車インターネットが高工インテリジェント車両ゴールデングローブ賞を受賞

12月15日から17日まで、2020年(第4回)高工インテリジェント自動車年次大会および高工ゴールデ...

...

...

ロボットの魚は本物の魚よりも速く泳ぎます!人間の心筋細胞から作られた紙の魚は108日間自律的に泳ぐことができる

米国のハーバード大学とエモリー大学の研究者らが協力し、ヒト幹細胞から抽出した心筋細胞を使った「人工魚...

AIがAIに勝つ: Googleの研究チームがGPT-4を使ってAI-Guardianのレビューシステムを打ち破る

8月2日、Googleの研究チームはOpenAIのGPT-4を使用して他のAIモデルのセキュリティ保...

AI言語モデルにおける幻覚バイアスのリスク

音声アシスタントからチャットボットまで、人工知能 (AI) はテクノロジーとのやり取りの方法に革命を...

AI技術がデータセンターの省エネに向けた新たな戦いに参入

序文: 2020年、データセンター建設は中央政府による新インフラ戦略に正式に組み込まれ、新インフラの...

英国は野生動物を追跡するために人工知能を使用し、鳴き声で30種の鳥を識別できる。

ロンドン動物学会(ZSL)は、英国で深刻化する生物多様性の問題に取り組むため、ネットワーク・レールと...

[トイレに座ってアルゴリズムを読む] アルゴリズム 8: 賢い隣接リスト (配列の実装)

前回は、空間と時間の複雑さがともにN 2であるグラフの隣接行列保存方法を紹介しました。今回は、グラフ...

ディープラーニングで知っておくべき活性化関数トップ10

みなさんこんにちは、ピーターです〜最近、reddit で非常に鮮明な mó xìng の写真を見まし...

中国と米国の人工知能の格差はどれほど大きいか:米国の人材総数は中国の約20倍

昨年上半期、メディアはかつてアンドリュー・ン氏が妻のために百度を去ったという話題を熱く議論していた。...