2016-07-09 7 views
2

私は正確に何が再帰であるかを理解しようとしており、以下の答えを見つけることができませんでした。再帰とは何ですか?

私が現在再帰を理解しているのは、メソッドがそれ自身を呼び出すときです。

すなわち

Menu() 
{ 
if(i<2) 
{Console.WriteLine();} 
else 
{Menu();}  
} 

上記自体を呼び出す方法再帰の例です。この方法は、それは、このまだ再帰で呼び出すメソッドを呼び出した場合

Menu() 
{ 
if(i<2) 
{Console.WriteLine();} 
else 
{Console.WriteLine("Something Went Wrong!"); MenuError();}  
} 

MenuError() 
{ 
Console.WriteLine("Something went wrong!"); 
Menu(); 
} 

:私はわからないんだけど何

は次のようなシナリオですか?

+1

再帰的であるかどうかわかりません。しかし、私はそれが間違いなく考慮されていることを知っている:[リエントラント](https://en.wikipedia.org/wiki/Reentrancy_(計算))(リエントラント関数は同じ呼び出しスタックによって2回目に呼ばれる関数です最初の呼び出しが完了する前に) –

+2

私には一連のメソッドがあるとします。あるメソッドから別のメソッドへ方向付けられた辺を描画するとします(すべてのコードが到達可能であると仮定します)。グラフ理論の観点からは、循環があるときはいつでも、自己であろうとなかろうと、再帰がある。 –

+0

http://www.etymonline.com/index.php?term=recursion同じスレッドが実行中の関数を呼び出すために遅かれ早かれ "後戻りする"場合、それは再帰です。あなたの例の間に概念的な違いはありません。ポイントは、以前の呼び出しから戻ってくる前に関数を再度呼び出すことです。 –

答えて

5

現在のところ、再帰の理解は、 というメソッドがいつでも呼び出されるということです。

これは間違いありません。再帰的定義は自己参照の定義です。

再帰的定義の2つの興味深い特性は、生産性および終了です。完全な出力が決して来ないかもしれないが(それは終わらないかもしれませんが)、プログラムは出力を続けていれば生産的です。有限時間内に完全な出力が得られれば、プログラムは終了します。

例えば、これは生産性、非終了のプログラムである。

Naturals(int i) { 
    Console.WriteLine(i); 
    Naturals(i + 1); 
} 

これは、終端プログラムである:

UpToTen(int i) { 
    Console.WriteLine(i); 
    if (i < 10) UpToTen(i + 1); 
} 

これは、非生産的なプログラムである:

DoNothing() { 
    DoNothing(); 
} 

MenuMenuErrorMenuErrorMenuとなり、という相互回帰と呼ばれることがあります。唯一の違いは私たちの組織です。 MenuErrorをインライン化することでコードを書き直すことができます。

Menu() { 
    if (i < 2) { 
    Console.WriteLine(); 
    } 
    else { 
    Console.WriteLine("Something Went Wrong!"); 
    Console.WriteLine("Something went wrong!"); 
    Menu(); 
    } 
} 

あなたは実際には抽象再帰自体ができ:ここで

// General definition 
A Fix<A>(Func<Func<A>,A> f) { 
    return f(() => Fix(f)); 
} 

// Special definition for void functions 
void Fix(Action<Action> f) { 
    f(() => Fix(f)); 
} 

void Menu(Action menu) { 
    if (i < 2) { 
    Console.WriteLine(); 
    } 
    else { 
    Console.WriteLine("Something Went Wrong!"); 
    Console.WriteLine("Something went wrong!"); 
    menu(); 
    } 
} 

Fix(Menu); 

は階乗関数を定義するために Fixを使用して別の例です。

Func<int, int> Fac(Func<Func<int, int>> fac) { 
    return i => i == 0 ? 1 : i * fac()(i - 1); 
} 

// Fix<Func<int, int>>(Fac) is the factorial function 

Fixではなく、署名A Fix<A>(Func<A,A> f)を持っていないなぜあなたは不思議に思うかもしれません。これは、C#が厳密な言語であるため、関数の適用を評価する前に引数を評価するためです。シンプルな署名では、C#プログラムは無限再帰で終了します。

+0

ありがとう本当に素晴らしい説明です! – Spooler

0

はいこれはまだ再帰です。テール再帰、ツリー再帰などのような再帰のさまざまなタイプがあります。あなたは安心してGoogleをチェックアウトすることができます。

ところで、2番目のケースでは、iの値が2以上の場合、それぞれが別のスタックオーバーフローエラーを呼び出すため、スタックオーバーフローエラーが発生します。

+1

それは実際には例の目的に過ぎませんでした。したがって、侵入は、メソッドが呼び出す何らかのメソッドを呼び出すときにだけです。 – Spooler

+1

@スプーラー:そうだと思います。 –

関連する問題