質問の歴史
再帰は、木の遍歴、階乗の計算、高速ソートのタスクをエレガントに解決するために頻繁に使用されるメカニズムです。C言語では、関数は自分自身を通常の名前呼び出しを通じて直接呼び出すことができるため、再帰呼び出しは直接的に実装されます。
問題
再帰は便利ですが、深いネストによるスタックの早期オーバーフローのリスクがあります(スタックオーバーフロー)。さらに、最適化がない巨大な入力データに対しては非効率的です(例えば、末尾再帰がないため)。
解決策
再帰の使用前に最大可能深度を確認し、ベースケースを実装し、メモリ(スタック)の使用を考慮し、重要な場合はアルゴリズムを反復型に書き換えることを検討します。
コード例:
// 階乗を再帰的に計算 unsigned long factorial(unsigned int n) { if (n <= 1) return 1; // ベースケース return n * factorial(n - 1); // 再帰ケース }
主な特徴:
C言語の関数は任意の名前で自分自身を直接呼び出すことができますか?
いいえ。関数は自分自身の名前を使ってだけ呼び出すことができ、呼び出しの時点でそれが定義されている必要があります(または少なくとも事前に宣言されている必要があります)。
再帰は常にループより効率的ですか?
いいえ!反復的な解決策はしばしばより速く、信頼性が高く、スタックを迅速に消費せず、関数呼び出しに追加のコストを必要としません。
再帰後、スタックは元の状態に戻りますか?
はい、スタックは各再帰関数の終了に伴って完全に解放されます。最外の関数が終了すると、メモリは元の状態に戻ります。
開発者は深さをチェックせずに100,000ノードの木の遍歴関数を再帰で実装しました。スタックオーバーフローが発生しました。
利点:
再帰深度をチェックし、深いネストを防ぐ保護を実装したアルゴリズムで、大きな遍歴をバッチに分けます(反復型)。
利点: