再起関数の簡単な例と説明をしてほしいのですが。
void Func(int num)
{
func(num-1);
printf(%d,num);
func(num-2);
}
ここをみられてはいかがでしょう
クイックソートの例があります。
http://www.ics.kagoshima-u.ac.jp/~fuchida/edu/algorithm/sort-algorithm/quick-
sort.html
# 普通は「再起」でなく「再帰」です.
こんな例ではどう?
void func( int num )
{
if( num < 0 ) // 終了条件:numが負なら終了
return;
printf( %d, num ); // numの値を表示してから
func( num - 1 ); // num-1を引数にしてfuncを呼び出す.
}
終了の条件がないと,メモリを使い切るまで再帰し続けて「再起」不能になります.
なんちゃって
リカーシブの話題ですね
ちょうど僕も再帰について疑問があったので
ちょっと割り込ませていただきます
いわゆる「ハノイの塔」をプログラムしていたんですが
少し不明な点があってvc++のヘルプをぐるぐるまわっていて疲れました..........笑
仕様は任意の盤の数を入力すれば
勝手に移動先の棒にすべて元通りに移動するものです
再帰を使って作ったんですが 盤が14個以上になるとどうしても勝手に終了してしまいま
す
13個以内なら正常に動作するんですけど..........???
原因はコードにあるのか はたまた再帰のネストが深すぎたためなのか???
経路はすべてトレースしてみたんですが どこにも異常がないようです
windowsでは再帰のネストが深すぎた場合
勝手に終了してしまうもんなんでしょうか?
ストールして終わりのような気もしますが
普通になにもせずなにごともないように終わってしまいます。
再帰のネストってどれくらいまでできるんでしょうか?
これからネスト回数を計測するコードを埋め込もうと思ってますけど
それが気になってしかたありません
どれくらいネストできるもんでしょうか?
再帰関数は、呼ばれた関数が終了する前にまた関数を呼ぶわけですから、再帰が終了す
るまでスタックが積まれる一方になります。
スタックメモリには上限がありますから、そこに達して異常終了した、ということが想
定されます。
VCの場合、スタックメモリの上限はデフォルトで1MBだったかなぁ?
chachaさん ありがとうございます
VC++でスタック容量を変えるにはどうすればいいんでしょう
ヘルプでそれらしき項目がありますが該当ファイルがなくてどうにも....
ところで再帰の場合、スタックに積むものは
その関数の自動、ローカルの使用変数の値など(ですよね 汗)
で 例えばint型を10使っていたら10*4byte=40byte
1MB==1000,000byteとしても1000,000/40==25,000
スタック領域を食いつぶすには25,000のネストが必要になるわけですか
でも実際にはもっと少ないようですが とすると
あれれ 一体スタックにはなにが積まれるんでしょ?
関数へのエントリポイントなんて4byteのLP32の世界だし....うーんよくわからん
笑
ハノイの塔を普通に作ると、再帰のネストは盤の枚数分です。
普通に作った場合に、13回や14回のネストでスタックを食いつぶすと
は思えないのですが。
> 経路はすべてトレースしてみたんですが どこにも異常がないようです
引数を1つ増やして、ネストの深さをトレースできるようにしたらどうな
ります?枚数を4位にして試してみた場合、どこまで深くなるでしょうか。
void func(int num)
{
if(num <= 2) return;
func(num-1);
printf(%d,num)
func(num-2);
}
void main()
{
FUnc(6);
}
この実行結果は何ですか?出来れば説明も・・・
>>かつ
丸投げすると答えてくれないんだよこういうコミュニティっていうのは。
サポートセンターじゃないんだから。
自分はどう思うのか、説明してみな。
それで『ここがわかりません』とか『これでいいのでしょうか』とかいってみな。
ちゃんと答えてくれるから。
> この実行結果は何ですか?出来れば説明も・・・
まず,実行してみたら?
その後,numに大きすぎない数(例えば5くらい)を渡したときにどうなるか,手順をひ
とつひとつ考えながら紙にでも書き出してみる.
それでも理解できない分からないところが残ったら,どこがどう分からないのかが読む
人が分かるように質問する.
このような努力の跡が見えなければ答えられませんなぁ.
最初にワタシが示した「簡単な例」にも何の反応もしてくれないし.
たいちろうさん ご指摘ありがとうございます
実は私のハノイの塔のコードは
完全にオリジナルなもので 手本となるコードと考え方を
今まで一度も見たことがなく(というかあえて見ないようにして)
作成したものです(楽しむためですけど..........笑)
私のコードは300行に渡る大きなものになってしまい..........汗
なにぶん素人なものですから
自分のコードでネスト回数を調べるコードを追加したところ
盤が4の場合の最大のネスト回数は 3, 2, 1回ということになりました
でも盤が6個の場合のネストは 17, 8, 3, 2, 1回となり
さらにやっていくと13個の盤だと
2683, 1333, 659, 325, 159, 77, 37, 17, 8, 3, 2, 1回のネストとなってしまい 笑
とはいえ14個でもこのペースだと単純に2をかけても(あまり深く考えないでください)
5000程度と思われ 確かにスタックを食いつぶすまでには至らないと私も思いました
しかしなんで14個になるととたんになにもしないで終了してしまうのか コード中の命令
をすべて実行するまでのトレースはしたものの(カバレッジ100%?)
14個での実行のトレースなんて人間業ではないですね(笑
こういうのはデバッグの手法の世界なんでしょうけど
トレーサで(VC++のブレークポイント設定のstep in等)トレースしていくのでは
この場合 ほとほとやんなっちゃってまして
次の検証方法について考えています←結構たのしいですね こういうのは
たいちろうさんのおっしゃる場合のコードは おそらく私とは比較にならない効率的な
コードだと思います。
そういった類のコードというのはホントにありますよねー。
たとえばうるう年を考慮したカレンダーを作成したときも 歴史的?なコードを見て私は
ぶっとびましたよ。
一行かよ..........というカンジで 笑
#include<stdio.h>
Hanoi(int ban,char A,char B,char C)
{
if ( ban > 0){
Hanoi(ban-1, A, C, B); /*;banー1の盤をBを利用してAからCへ移動*/
printf(move %d th disk from %c to %c \n,ban,A,B);
Hanoi(ban-1, C, B, A); /*;banー1の盤をAを利用してCからBへ移動*/
}
}
main()
{
int ban;
printf(banber of Disks: );
scanf(%d,&ban);
Hanoi(ban,'A','B','C'); /*;banの盤をCを利用してAからBへ移動*/
}
こういうコードがハノイの塔の模範的なコードなんですね。
これなら確かにネストは激減します
このコードはただ移動の過程が文字列で表示されるだけなのでつまらないですけど
私が今回作ったのものはやはり模範例のアルゴリズムと多少異なっていました
しかしアルゴリズム(考え方)の選択でこうも明確な差が出てしまう好例になりました
うーん やっぱり自分で考えて作るというのも限界があるなあ
他人の例をもっといっぱい知ることが重要なのを再認識しました
もっとたくさんコード書きたいです
暇つぶしにやってみました。
自分の頭でシミュレートすると面倒くさいですね。
関数動作
main()
+-func(6)
+-func(5)
| +-func(4)
| | +-func(3)
| | | +-func(2)
| | | +-printf出力 3
| | | +-func(1)
| | +-printf出力 4
| | +-func(2)
| +-printf出力 5
| +-func(3)
| +-func(2)
| +-printf出力 3
| +-func(1)
+-printf出力 6
+-func(4)
+-func(3)
| +-func(2)
| +-printf出力 3
| +-func(1)
+-printf出力 4
+-func(2)
出力結果
3
4
5
3
6
3
4
なんかたびたびですみません
VC++でのスタックサイズの変更は
BUFSIZマクロを変えればいいようです
私の作ったプログラムではSTDIO.Hをインクルードしています
このヘッダの中に
BUFSIZ 512
の記述がありました
ためしに
#ifdef BUFSIZ
#define BUFSIZ 1024
#endif
としたところ
うまく14個目の盤のグラフィック表示がなされました
どうやら原因は標準でのスタック領域あふれのようでした
しかし効率の悪いアプリを作ってぬか喜びしてたところに
強烈なフックをいただきました
歴史的?コードを追うと
再帰の呼び出しがN個+1回で済んでしまい
その再帰を表にすると 完全なバランス木になっている上
再帰関数のパラメタの妙でうまく移動先をシフトしているところなど
もう神がかり的な印象を持ってしまいました
ただ バランス木で個々の三角形を見ると 以外と単純であることがわかりましたが
それ以上の分析がまだできません
いずれにしても 前に書いたコードは(私のコードではありません)本当にスゴイ!!
BUFSIZはsetbuf標準C関数を使うときに,バッファに必要なサイズです。
勝手に変更してはいけません。
スタック容量の変更は,一応リンカオプションでできたはずです。