![](http://oshiete.xgoo.jp/images/v2/pc/qa/question_title.png?e6f04cf)
C言語のプログラムについてです。
テキストからランダムに並べられたアルファベットを順番にひっぱってきて、
二分木の構造にアルファベットをアルファベット順に格納していき、その順番で表示するプログラムなのですが、
typedef struct rec{
char word[1];
struct rec *left;
struct rec *right;
}rec;
という構造体が定義されており、
二分木構造に(なるように)アルファベットを順番に格納していったあと、
それをアルファベット順に表示していく関数が以下の関数hyoujiなのですが、
(二分木を生成する際にmallocを使用しているので、freeがありますが今回は無視してください。)
void hyouji(rec *top){
if(top!= NULL){
hyouji(top->left);
printf("%s\n",top->word);
hyouji(top->right);
free(top);
}
}
この再帰呼び出しの動きがよくわかりません。(つまりはhyoujiの関数の動きがわかりません。)
*topは二分探索木の一番上のアドレスを示しています。
wordにアルファベットが格納されています。
たとえば、下のように格納されていたらどのようにhyouji関数は動くのでしょうか。
順番に説明していっていただけたらありがたいです。
(ちなみにプログラム的に下の例のように格納されていきます。
まずtopを生成して、テキストファイルの先頭のアルファベットを入れて、そこから順に
格納していくので、topがaとは限りません。)
........................[b]
..................../...\
.................[a]........[e]
.........................../...\
.......................[c].........[g]
No.3ベストアンサー
- 回答日時:
落ち着いて、よく考えてください。
「見ての通り、hyouji(top->left);の後、hyouji(top->right);の前です。」と書きました。
「top->left全体の表示」の後
「top->right全体の表示」の前
に、top自身だけのprintfです。
これが
void hyouji(rec *top){
if(top!= NULL){
hyouji0(top->left);
printf("%s\n",top->word);
hyouji0(top->right);
free(top);
}
}
なら、実行順番わかりますよね?
No.5
- 回答日時:
No.4に対して2点補足。
----------------
1点目。
(1) 左の人を呼び出す(左の人にバトンを渡す)
(2) (左の人から自分にバトンが戻ってきたら)自分のwordを表示する
(3) 右の人を呼び出す(右の人にバトンを渡す)
(4) 自分を呼び出した呼び出し元にバトンをもどす
という箇所の(4)は,(2)の表記に合わせて次のように書いた方がよかったです。
(4) (右の人から自分にバトンが戻ってきたら)自分を呼び出した呼び出し元にバトンをもどす
----------------
2点目。
(1)○の左は存在しないのでバトンはそのまま
という箇所は単純にこう説明したけれど,存在しないかどうか判定しているのは本当は自分ではなく,次のようになります。
↓左の人を呼び出す
↓呼び出してみたら if (top != NULL) で左の人は存在しないことが判明
↓そのまま呼び出し元に戻る
No.4
- 回答日時:
再帰をイメージする際,
「自分自身を呼び出す」のように自分にループして戻ってくるイメージで捉えると,同じ場所をぐるぐる回って何回目の呼び出しか自分でも区別していないイメージになるので,
「自分のクローンを生み出してそれを呼び出す。用が済んだらそのクローンは消える」のように,「自分のコピーという“別人”」を呼び出すイメージで捉えると分かりやすいように思います。
(1) hyouji(top->left);
(2) printf("%s\n",top->word);
(3) hyouji(top->right);
(4) }
というコードは(1)→(2)→(3)→(4)の順に処理が進んでいくのだけれど,陸上競技の400mリレー走よろしく,現在その箇所を実行中であることをバトンの有無で示すならば,次のような比喩で説明できます。
(1) 左の人を呼び出す(左の人にバトンを渡す)
(2) (左の人から自分にバトンが戻ってきたら)自分のwordを表示する
(3) 右の人を呼び出す(右の人にバトンを渡す)
(4) 自分を呼び出した呼び出し元にバトンをもどす
........................[b]
..................../...\
.................[a]........[e]
.........................../...\
.......................[c].........[g]
ですから,上記の二分木の根(root)を起点に,この規則にしたがって木を走査すると,次の流れを上から一つずつ順に追った処理になります。
(0) [現在位置はb]
(1) 左のaにバトンを渡す
........(0) [現在位置はa]
........(1)aの左は存在しないのでバトンはそのまま
........(2)「私はa」と表示★
........(3)aの右は存在しないのでバトンはそのまま
........(4)呼出元bにバトンをもどす
(2)「私はb」と表示★
(3) 右のeにバトンを渡す
........(0) [現在位置はe]
........(1)左のcにバトンを渡す
................(0) [現在位置はc]
................(1)cの左は存在しないのでバトンはそのまま
................(2)「私はc」と表示★
................(3)cの右は存在しないのでバトンはそのまま
................(3)呼出元eにバトンをもどす
........(2)「私はe」と表示★
........(3)右のgにバトンを渡す
................(0) [現在位置はg]
................(1)gの左は存在しないのでバトンはそのまま
................(2)「私はg」と表示★
................(3)gの右は存在しないのでバトンはそのまま
................(3)呼出元eにバトンをもどす
........(3)呼出元bにバトンをもどす
(4)呼出元にバトンを戻す(一連の処理の終了)
No.2
- 回答日時:
再帰呼び出しを理解するコツは、呼び出した先のことは考えないで、機能だけを考える、ということだと思います。
これは、普段からやっていることでもあります。
printfが中でどんな動きをしているか、考えて使ってますか?「指定した書式で出力する」って「機能」だけを考えているのではないでしょうか。
また、同じ行を実行しているので、「(ループのように)戻ってくる」と考えると、混乱の元です。
呼び出されたhyoujiと呼び出したhyoujiは、#1にあるように「機能はまったく同じの、別の関数」だと考えましょう。
void hyouji(rec *top){
if(top!= NULL){
/*
top->leftを「hyouji」する。
今実行している「hyouji」ではなく、別の「hyouji」が実行される
中でどうなっているかは、ひとまず置いておく
*/
hyouji(top->left);
/* top->world をprintfで出力 */
printf("%s\n",top->word);
/*
top->rightを「hyouji」する。
今実行している「hyouji」ではなく、別の「hyouji」が実行される
中でどうなっているかは、ひとまず置いておく
*/
hyouji(top->right);
}
}
> どのタイミングでPrintfが実行されるのでしょうか。
見ての通り、hyouji(top->left);の後、hyouji(top->right);の前です。
hyouji(top->left);やhyouji(top->right);の中でprintfが実行されているかもしれませんが、それは「別の関数」なので、関係ありません。
> Printfでこけてしまうとはどういうことでしょうか?
char word[1];
に格納できる「文字列」は、何文字までだと思いますか?
文字列には、本体の文字列の他に'\0'が必要です。少なくとも、printfの書式%sは、「'\0'で終わる文字列」を必要とします。
あるいは、1文字だけなら、「文字列」である必要はありません。charで文字だけ記憶して、%cを使う、という方法もあります。
この回答への補足
ただ、そうなるとtop、(top)のleft、(top)のrightが表示されてから、つまり今回の木の例だと[b]、[a]、[e]の順に表示されてしまいそうですが、(実際はabcegとできている)どこで理解が間違えているのでしょうか。
何度も申し訳ありません。
printfがこける に関してはそのとおりです。
指摘ありがとうございます。
No.1
- 回答日時:
これ, printf でこけるよね.
さておき.
top が b を指すとしたら
・a を指すポインタを使って hyouji を呼び出す
・printf を実行する
・e を指すポインタを使って hyouji を呼び出す
というだけですが....
わかりにくかったら, hyouji をコピーして
void hyouji0(rec *top){
if(top!= NULL){
hyouji1(top->left);
printf("%s\n",top->word);
hyouji1(top->right);
free(top);
}
}
void hyouji1(rec *top){
if(top!= NULL){
hyouji2(top->left);
printf("%s\n",top->word);
hyouji2(top->right);
free(top);
}
}
(以下略)
としてみたら?
この回答への補足
回答ありがとうございます。
どのタイミングでPrintfが実行されるのでしょうか。
質問に質問をかさねてすいません。
あと、Printfでこけてしまうとはどういうことでしょうか?
どこか不都合な点があったりしますか
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- 大学・短大 C言語線形リストの問題です 3 2022/12/22 00:45
- C言語・C++・C# C言語初心者 構造体 課題について 2 2023/03/10 19:48
- C言語・C++・C# 10人分の生徒の英語の点数{32,34,41,38,40,26,14,46,42,50} と数学の点 2 2022/05/26 21:31
- C言語・C++・C# C言語プログラム変更 2 2022/12/21 15:03
- C言語・C++・C# スタックフレームの消滅 6 2023/05/20 12:33
- Visual Basic(VBA) EXCEL VBAで教えてください。 1 2022/12/22 04:20
- Excel(エクセル) 【エクセルマクロ】既に開いているIEの、サイズや表示位置を変更するには 4 2022/12/01 22:57
- JavaScript スマフォではボタンを表示させたくない 2 2023/01/20 14:26
- オープンソース cssで中央寄せ 1 2023/05/19 06:25
関連するカテゴリからQ&Aを探す
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
Enterキーを押されたら次の処理...
-
C言語で複数列のデータを1列の...
-
終了条件Ctrl+zについて,結果表...
-
C言語のプログラムで、途中で止...
-
printf による16進表示について
-
fread(),fwrite()等について
-
char型2つを結合し、short型に...
-
【C言語】全角文字の配列を、全...
-
なぜ無限ループになるかが分か...
-
空白を含んだ文字列がうまく格...
-
0x8, スペース, 0x8をプログラ...
-
#defineが使用するメモリ領域に...
-
リストの作成と出力(C言語)
-
プログラミングの授業の課題です
-
矢印キーを押下してコンソール...
-
「指定されたキャストは有効で...
-
2曲同時再生するにはどうした...
-
Aの値からBの値を除するとは??
-
C言語での引数の省略方法
-
数字以外が入力されたらエラー...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
Enterキーを押されたら次の処理...
-
#defineが使用するメモリ領域に...
-
C言語のプログラムで、途中で止...
-
printf による16進表示について
-
空白を含んだ文字列がうまく格...
-
プログラミングの授業の課題です
-
【C言語】全角文字の配列を、全...
-
構造体メンバの初期化
-
Cでファイルの行数をカウントす...
-
char型2つを結合し、short型に...
-
矢印キーを押下してコンソール...
-
C言語で複数列のデータを1列の...
-
終了条件Ctrl+zについて,結果表...
-
Ç言語でファイルサイズを変更す...
-
エラーについて質問です。
-
C言語でのCSVファイルの読み出...
-
C++で指定文字列のカウント方法...
-
VC++でSQLへSELECT文を送ったの...
-
fscanfの使い方
-
c言語で文書を読み込み、単語の...
おすすめ情報