質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

再帰

情報工学における再帰とは、プログラムのあるメソッドの処理上で自身のメソッドが再び呼び出されている処理の事をいいます。

Q&A

解決済

4回答

1363閲覧

[再帰]ハノイの塔のプログラム 図として表現したい

riiiiii__ru

総合スコア5

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

再帰

情報工学における再帰とは、プログラムのあるメソッドの処理上で自身のメソッドが再び呼び出されている処理の事をいいます。

0グッド

1クリップ

投稿2019/10/03 06:48

編集2019/10/03 07:41

c

1#include <stdio.h> 2int k=0; 3void Hanoi(int n,char *X,char *Y,char *Z){ 4 if(n>=2) 5 Hanoi(n-1,X,Z,Y); 6 k++; 7 printf("Step %d;move %d from %s to %s \n",k,n,X,Z); 8 if(n>=2) 9 Hanoi(n-1,Y,X,Z); 10} 11 12int main(void){ 13 Hanoi(3,"A","B","C"); 14 return 0; 15 } 16 17 18 19```### このハノイの塔のプログラムから改良して以下のように図にしたいです。 20 21//A: 3 2 1 22//B: 23//C: 24//----- 25//A: 3 2 26//B: 27//C: 1 28//----- 29 30### 補足情報 31 32プログラミング初心者です。 33よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2019/10/03 06:54 編集

Step 1 ;move 1 from A to C Step 2 ;move 2 from A to B Step 3 ;move 1 from B to A Step 4 ;move 3 from A to C Step 5 ;move 1 from C to B Step 6 ;move 2 from C to A Step 7 ;move 1 from A to C 実行すると上記のようになりましたが、間違っていませんか? Step 3 で C にあるはずの 1 が B から移動しています。 そして 1 の下にある 3 が Step 4 で移動しています。
riiiiii__ru

2019/10/03 07:17 編集

#include <stdio.h> void Hanoi(int n,char *X,char *Y,char *Z){ if(n>=2) Hanoi(n-1,X,Z,Y); printf("Step ;move %d from %s to %s \n",n,X,Z); if(n>=2) Hanoi(n-1,Y,X,Z); } int main(void){ Hanoi(3,"A","B","C"); return 0; } このプログラムなら正常に実行できますが、step数の出し方がわからないです。
Zuishin

2019/10/03 07:16

ステップ数は Hanoi 関数が呼び出されるたびに 1 増えているだけです。
Zuishin

2019/10/03 07:18

新しい方のコードも終了条件が無いので正常に実行できません。 実際にコンパイルして動かしていますか?
riiiiii__ru

2019/10/03 07:24

#include <stdio.h> int k; void Hanoi(int n,char *X,char *Y,char *Z){ if(n>=2) Hanoi(n-1,X,Z,Y); printf("Step %d;move %d from %s to %s \n",k,n,X,Z); if(n>=2) Hanoi(n-1,Y,X,Z); k++; } int main(void){ Hanoi(3,"A","B","C"); return 0; } 実行するとこうなっています。どこを修正すればいいのでしょうか、、。 Step 0;move 1 from A to C Step 1;move 2 from A to B Step 1;move 1 from C to B Step 3;move 3 from A to C Step 3;move 1 from B to A Step 4;move 2 from B to C Step 4;move 1 from A to C
Zuishin

2019/10/03 07:31

今度は動きましたが、ステップが違います。 初期化されていないので、まず int k; を int k = 0; に変えてください。それから k++; を printf の直前の行に持ってきてください。
riiiiii__ru

2019/10/03 07:33

出来ました。 本当にありがとうございます。
Zuishin

2019/10/03 07:38 編集

質問を編集してコードを書き換えてください。その際は ```C int main(void) { ... ... ``` のように、```C と ``` の間にコードを入れてください。` はバッククォートです。<code> ボタンを押すと出てきます。 このようにすると、#include の前の / は要りませんし、インデントも正しく表示されます。
riiiiii__ru

2019/10/03 07:42

これでよろしいでしょうか、、?
Zuishin

2019/10/03 07:43

main の最後の } の位置がおかしいですが、あとは OK です。
guest

回答4

0

ベストアンサー

きったねぇけど、動くっちゃ動く。

C

1#include <stdio.h> 2#include <string.h> 3 4char disk[3][10]; 5 6void Hanoi(int n,char* X, char* Y, char* Z) { 7 char tmp; 8 if(n>=2) 9 Hanoi(n-1,X,Z,Y); 10 11 /* Xの円盤をZに移動する */ 12 tmp = X[strlen(X)-1]; 13 X[strlen(X)-1] = '\0'; 14 Z[strlen(Z)] = tmp; 15 printf("//A:%s\n//B:%s\n//C:%s\n//----------\n", disk[0], disk[1], disk[2]); 16 17 if(n>=2) 18 Hanoi(n-1,Y,X,Z); 19} 20 21int main(void){ 22 strcpy(disk[0],"321"); 23 strcpy(disk[1],""); 24 strcpy(disk[2],""); 25 Hanoi(3,disk[0],disk[1],disk[2]); 26 return 0; 27}

投稿2019/10/03 11:44

編集2019/10/03 11:53
episteme

総合スコア16614

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

episteme

2019/10/03 12:09

念のため、main()のアタマでdisk[3][10]を全部'\0'で埋めたほうがいいかなー...
riiiiii__ru

2019/10/03 17:11

分かりました。 わざわざご丁寧にありがとうございます。 参考にさせていただきます。
rubato6809

2019/10/03 22:29 編集

> 全部'\0'で埋めたほうがいいかな 現状のdisk配列はグローバル変数ですから、既にオール0に初期化されていて問題起こしません。 0クリアされない場合は、ディスクを移動する箇所に一行追加するのがインパクト少なくて済みそうです、もちろんstrlen()を4度も呼ぶのはどうかと思いますが。 tmp = X[strlen(X)-1]; X[strlen(X)-1] = '\0'; Z[strlen(Z)+1] = '\0'; // この行を追加 Z[strlen(Z)] = tmp;
kazuma-s

2019/10/04 05:05

strlen の結果を憶えておけば、呼び出しは 2回で済みます。 int lenX = strlen(X)-1, lenZ = strlen(Z); Z[lenZ] = X[lenX]; Z[lenZ+1] = X[lenX] = '\0';
Zuishin

2019/10/04 05:07

釈迦に説法……
rubato6809

2019/10/04 08:33

釈迦です。 この程度の処理であればstrlen()を何度呼んでも大した負荷ではないと思いますが、、、初心者は工夫できることをいろいろ試すと良いですよ。 例えば、(strlen()する代りに)disk[0]~disk[2]、それぞれの枚数を記録するというアイディアが考えられると思います。"321" ならスタート時点は3枚、0枚、0枚ですね。 質問者さんは、枚数をどこにどう持てば良いか、ディスクを移動するところをどう書けば良いか、考えてみると良いと思います。やり方はひとつではないので、急がなくて結構。
episteme

2019/10/04 11:05

C++ならstd::stringで楽できるんだけどねー... Z.push_back(X.back()); X.pop_back(); こんだけやし。
guest

0

c

1#include <stdio.h> 2#include <string.h> 3 4char a[3][10]; //多次元配列// 5 6void Hanoi(int n,char* X, char* Y, char* Z) { 7 char tmp; 8 if(n>=2) 9 Hanoi(n-1,X,Z,Y); 10 11 tmp = X[strlen(X)-1]; // Xの円盤をZに移動 // 12 X[strlen(X)-1] = '\0'; //Xについての文字数// 13 Z[strlen(Z)+1] ='\0'; 14 Z[strlen(Z)] = tmp; //Zについての文字数// 15 printf("A:%s\nB:%s\nC:%s\n-----\n", a[0], a[1], a[2]); 16 17 if(n>=2) 18 Hanoi(n-1,Y,X,Z); 19} 20 21int main(void){ 22 strcpy(a[0],"321"); //文字列のコピー// 23 strcpy(a[1],""); 24 strcpy(a[2],""); 25 Hanoi(3,a[0],a[1],a[2]); 26 return 0; 27}

文字列や単語の意味を理解しながら自分なりに変えてみました。

投稿2019/10/04 03:25

riiiiii__ru

総合スコア5

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2019/10/04 03:50 編集

次のような状態だとします。 X = "21"; Z = "3"; 文字列の最後には必ずそこで終わりということを示す終端文字 '\0' が入っています。 よって次のように表すことができます。(疑似コード) X = '2' + '1' + '\0' + (不明な文字) + (不明な文字)... Z = '3' + '\0' + (不明な文字) + (不明な文字)... この時 tmp = X[strlen(X)-1]; // X の最後の文字を tmp に退避 // tmp == '1' になる X[strlen(X)-1] = '\0'; // X の最後の文字を削除 // '1' のあった場所に '\0' を書き込むので、そこで文字列が終わる // X は '2' + '\0' + '\0' + (不明な文字) + (不明な文字)... になる Z[strlen(Z)+1] ='\0'; // Z の文字数を増やすのであらかじめ終端文字を置いておく // Z は '3' + '\0' + '\0' + (不明な文字)... になる Z[strlen(Z)] = tmp; // Z の最後に tmp を付け加える // Z は '3' + '1' + '\0' + (不明な文字)... になる
rubato6809

2019/10/04 08:37 編集

実際に動きを描いてみるというのは良い発想です。 そこで釈迦から追加課題を授けましょう(笑)。 a[3][10] としたのは、ディスクを最大9枚まで重ねられるため、ですよね? "321" 固定じゃつまらない。では "54321" にするなら、どうしますか? プログラムを実行する時にディスクの枚数を指定するには、どうしますか? strlen()する代りに、3ヵ所のディスクの枚数を記録しながら動かす件も、今は工夫し甲斐あると思うので考えてみてください。いずれも急がなくて結構。
Zuishin

2019/10/04 08:47

なんとなく私が質問者だと思われているように感じるので、一応否定しておきます。
guest

0

これ、分かりますか?

C

1#include <stdio.h> 2 3int k; 4int a[3][32]; // A,B,C の 3個所。a[i][0] は円盤の枚数。残りの 1~31 は円盤の番号 5 6void print(void) 7{ 8 for (int i = 0; i < 3; i++) { 9 printf("//%c:", 'A' + i); 10 for (int j = 1; j <= a[i][0]; j++) 11 printf(" %d", a[i][j]); 12 putchar('\n'); 13 } 14 printf("//---- [%d]\n", ++k); 15} 16 17void init(int n) 18{ 19 k = 0; 20 a[0][0] = n, a[1][0] = 0, a[2][0] = 0; // A は n枚、B, C は 0枚 21 for (int i = 0; i < n; i++) 22 a[0][i + 1] = n - i; // A に円盤を n, ... 2, 1 と置く 23 print(); 24} 25 26void Hanoi(int n, int x, int y, int z) 27{ 28 if (n > 1) Hanoi(n - 1, x, z, y); 29 a[z][++a[z][0]] = a[x][a[x][0]--]; 30 print(); 31 if (n > 1) Hanoi(n - 1, y, x, z); 32} 33 34int main(void) 35{ 36 int n = 3; 37 init(n); 38 Hanoi(n, 0, 1, 2); 39 return 0; 40}

投稿2019/10/03 12:21

kazuma-s

総合スコア8224

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

riiiiii__ru

2019/10/03 17:15

ご回答ありがとうございます。 説明されていることは何となく分かるのですが、for文の部分でエラーが出てしまって実装できないです、、。
kazuma-s

2019/10/03 19:39

とても古い規格の Cコンパイラを使っていますね。int i, j; を先に書いて、for文の中に int を書かないように修正してください。
guest

0

こんな感じでは如何でしょう.
初心者に見せられるコードとは言い難いですが...。

c

1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4void print(char** t,int n,char **o){ 5 int i,j; 6 for(j=0;j<3;j++){ 7 printf("%s:",o[j]); 8 for(i=n-1;i>=0;i--) if(t[i]==o[j]) printf(" %d",i+1); 9 printf("\n"); 10 } 11 printf("-----\n"); 12} 13void move(int r,char *x,char *y,char *z,char **t,int n,char **o){ 14 if(r>=2) move(r-1,x,z,y,t,n,o); 15 t[r-1]=z; //r番をzに移動 16 print(t,n,o); 17 if(r>=2) move(r-1,y,x,z,t,n,o); 18} 19void hanoi(int n,char *x,char *y,char *z){ 20 int i; 21 char *o[3]; o[0]=x; o[1]=y; o[2]=z; //表示用 22 char **t=(char **)malloc(sizeof(char*)*n); //各円盤の位置 23 for(i=0;i<n;i++) t[i]=x; 24 print(t,n,o); 25 move(n,x,y,z,t,n,o); 26 free(t); 27} 28int main(void){ 29 hanoi(3,"A","B","C"); 30 return 0; 31}

plain

1A: 3 2 1 2B: 3C: 4----- 5A: 3 2 6B: 7C: 1 8----- 9A: 3 10B: 2 11C: 1 12----- 13A: 3 14B: 2 1 15C: 16----- 17A: 18B: 2 1 19C: 3 20----- 21A: 1 22B: 2 23C: 3 24----- 25A: 1 26B: 27C: 3 2 28----- 29A: 30B: 31C: 3 2 1 32-----

投稿2019/10/03 11:35

編集2019/10/03 11:54
jimbe

総合スコア12623

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

riiiiii__ru

2019/10/03 17:13

ご回答ありがとうございます。 初心者の私には少し難しいです、、。 時間をかけて理解します。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問