再帰関数の効率の問題は、末尾再帰最適化 (TCO) テクノロジーによって解決できます。 C コンパイラは TCO をサポートしていませんが、[__tail_recursive](https://en.cppreference.com/w/cpp/keyword/tail_recursive) キーワードを通じてこの動作をシミュレートし、再帰呼び出しを反復に変換することができます。 TCO は、再帰呼び出しが関数の最後の操作である場合に適用されます。新しい状態値と末尾再帰呼び出しインジケーターを返すタプルを使用して実装され、スタック フレーム作成のオーバーヘッドが排除され、効率が向上します。
C 関数の再帰的実装: 末尾再帰最適化テクニックの使用に関する実践ガイド
再帰は、それ自体を A と呼ぶ関数です。データ構造のトラバースや解決策の検索など、特定の種類の問題を解決するときに役立つプロセス。ただし、再帰により多くの関数呼び出しスタックが作成されるため、プログラムの効率が低下する可能性があります。これは、大規模なデータ セットを扱う場合に特に懸念されます。
末尾再帰最適化
末尾再帰最適化 (TCO) は、最後の操作として再帰呼び出しがある場合に、再帰を関数に変換するコンパイラ手法です。反復に変換され、スタック フレーム作成のオーバーヘッドが排除されます。これは、再帰呼び出しが多い関数にとって重要です。
C
C コンパイラでの TCO の実装は通常、TCO をサポートしませんが、[__tail_recursion
](https://en.cppreference) を使用できます。 .com/w/cpp/keyword/tail_recursive) キーワードは次の動作をシミュレートします:
#include <utility> template <typename F, typename T, typename... Args> std::pair<bool, T> tail_recursive(F&& f, T&& x, Args&&... args) { while (true) { const bool is_tail_call = false; const auto result = f(std::forward<T>(x), std::forward<Args>(args)...); if constexpr (!is_tail_call) { return result; } x = std::move(std::get<0>(result)); f = std::move(std::get<1>(result)); } }
tail_recursive
関数は関数オブジェクト f
、初期状態 x## を受け取ります。 # および追加パラメータ
args。最初の要素が末尾再帰呼び出しを行うかどうかを示し、2 番目の要素が新しい状態値であるタプルを返します。現在の呼び出しが末尾再帰呼び出しでない場合は、結果が返されます。そうでない場合は、新しい状態値と更新された関数呼び出しを使用して再帰呼び出しが行われます。
実践的なケース
階乗を計算するための次の再帰関数を考えてみましょう:int factorial(int n) { if (n == 0) { return 1; } return n * factorial(n - 1); }TCO を使用して末尾再帰に変換します:
auto factorial_tail_recursive(int n) { auto f = [&](int x, int y) -> std::pair<bool, int> { if (x == 0) { return {false, y}; } return {true, y * x}; }; return tail_recursive(f, 1, n); }この末尾再帰バージョンでは、内部関数
f は最初の要素が末尾再帰呼び出しを行うかどうかを示し、2 番目の要素が新しい状態値であるタプルを返します。
f が呼び出されるたびに、状態
y が更新され、末尾再帰呼び出しを行うかどうかを示すブール値が返されます。
注: TCO はすべての再帰関数に適用できるわけではありません。再帰呼び出しが関数の最後の操作である場合にのみ使用できます。
以上がC++ 関数の再帰的実装: 末尾再帰最適化手法を使用するには?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。