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

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

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

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

Q&A

解決済

3回答

1155閲覧

C言語:クイックソートのトレースで分からないところ

sanshirou

総合スコア8

C

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

0グッド

0クリップ

投稿2021/09/09 15:30

前提・実現したいこと

C言語のクイックソートのプログラムのトレースを行っています。
そこで、どうしても理解できない疑問が起こりました。

発生している問題・エラーメッセージ

下記の「実行結果」で、(*10)→(*6)、および、(*10)→(*9)にジャンプする箇所があるのですが、なぜそんなことになるのか、いくら考えても分かりません。いろいろprintf()を埋め込んでいって、もうわけが分からなくなってしまいました。

該当のソースコード

C

1#include <stdio.h> 2#include <stdlib.h> 3 4#define N 10 5 6void qksort(int d[], int top, int end); 7 8int main(void) 9{ 10 int i; 11 int d[] = {11081, 5137, 24671, 5233, 26229, 12 14891, 25719, 11578, 5160, 4907}; 13 14 printf("【整列前】\n"); 15 for (i = 0; i < N; i++) 16 printf("%d ", d[i]); 17 printf("\n"); 18 19 qksort(d, 0, N - 1); 20 21 printf("【整列後】\n"); 22 for (i = 0; i < N; i++) 23 printf("%d ", d[i]); 24 printf("\n"); 25 return EXIT_SUCCESS; 26} 27 28void qksort(int d[], int top, int end) 29{ 30 int key, wk, i, j; 31 int k; /* デバッグ用 */ 32 33 printf("(*1)\n"); /* デバッグ用 */ 34 key = d[(top+end)/2]; 35 printf("key = %d\n", key); /* デバッグ用 */ 36 i = top - 1; 37 j = end + 1; 38 while (1) { 39 printf("(*2)\n"); /* デバッグ用 */ 40 while (d[++i] < key) 41 ; 42 printf("i = %d\n", i); /* デバッグ用 */ 43 while (d[--j] > key) 44 ; 45 printf("j = %d\n", j); /* デバッグ用 */ 46 if (i >= j) 47 break; 48 wk = d[i]; 49 d[i] = d[j]; 50 d[j] = wk; 51 for (k = 0; k < N; k++) /* デバッグ用 */ 52 printf(" %d", d[k]); /* デバッグ用 */ 53 printf("\n\n"); /* デバッグ用 */ 54 } 55 printf("(*3)\n"); /* デバッグ用 */ 56 printf("top = %d, i-1 = %d\n", top, i-1); /* デバッグ用 */ 57 printf("(*4)\n"); /* デバッグ用 */ 58 if (top < i-1) { 59 printf("(*5)\n"); /* デバッグ用 */ 60 printf("qksort(d, %d, %d);\n", top, i-1); /* デバッグ用 */ 61 qksort(d, top, i - 1); /* 左半分をクイックソート */ 62 } 63 printf("(*6)\n"); /* デバッグ用 */ 64 printf("j+1 = %d, end = %d\n", j+1, end); /* デバッグ用 */ 65 printf("(*7)\n"); /* デバッグ用 */ 66 if (j+1 < end) { 67 printf("(*8)\n"); /* デバッグ用 */ 68 printf("qksort(d, %d, %d);\n", j+1, end); /* デバッグ用 */ 69 qksort(d, j + 1, end); /* 右半分をクイックソート */ 70 } 71 printf("(*9)\n"); /* デバッグ用 */ 72 printf("(*10)\n"); /* デバッグ用 */ 73}

試したこと

すでに上のソースコードに埋め込んでありますが、printf()を使って実行の流れを可視化させました。その実行結果を、下に示します。

(実行結果)

【整列前】 11081 5137 24671 5233 26229 14891 25719 11578 5160 4907 (*1) key = 26229 (*2) i = 4 j = 9 11081 5137 24671 5233 4907 14891 25719 11578 5160 26229 (*2) i = 9 j = 8 (*3) top = 0, i-1 = 8 (*4) (*5) qksort(d, 0, 8); (*1) key = 4907 (*2) i = 0 j = 4 4907 5137 24671 5233 11081 14891 25719 11578 5160 26229 (*2) i = 1 j = 0 (*3) top = 0, i-1 = 0 (*4) (*6) j+1 = 1, end = 8 (*7) (*8) qksort(d, 1, 8); (*1) key = 11081 (*2) i = 2 j = 8 4907 5137 5160 5233 11081 14891 25719 11578 24671 26229 (*2) i = 4 j = 4 (*3) top = 1, i-1 = 3 (*4) (*5) qksort(d, 1, 3); (*1) key = 5160 (*2) i = 2 j = 2 (*3) top = 1, i-1 = 1 (*4) (*6) j+1 = 3, end = 3 (*7) (*9) (*10) (*6) j+1 = 5, end = 8 (*7) (*8) qksort(d, 5, 8); (*1) key = 25719 (*2) i = 6 j = 8 4907 5137 5160 5233 11081 14891 24671 11578 25719 26229 (*2) i = 8 j = 7 (*3) top = 5, i-1 = 7 (*4) (*5) qksort(d, 5, 7); (*1) key = 24671 (*2) i = 6 j = 7 4907 5137 5160 5233 11081 14891 11578 24671 25719 26229 (*2) i = 7 j = 6 (*3) top = 5, i-1 = 6 (*4) (*5) qksort(d, 5, 6); (*1) key = 14891 (*2) i = 5 j = 6 4907 5137 5160 5233 11081 11578 14891 24671 25719 26229 (*2) i = 6 j = 5 (*3) top = 5, i-1 = 5 (*4) (*6) j+1 = 6, end = 6 (*7) (*9) (*10) (*6) j+1 = 7, end = 7 (*7) (*9) (*10) (*6) j+1 = 8, end = 8 (*7) (*9) (*10) (*9) (*10) (*9) (*10) (*6) j+1 = 9, end = 9 (*7) (*9) (*10) 【整列後】 4907 5137 5160 5233 11081 11578 14891 24671 25719 26229

補足情報(FW/ツールのバージョンなど)

OSはWindows10、コンパイラはVisual Studio2012です。

前提・実現したいこと

C言語のクイックソートのプログラムのトレースを行っています。
そこで、どうしても理解できない疑問が起こりました。

発生している問題・エラーメッセージ

下記の「実行結果」で、(*10)→(*6)、および、(*10)→(*9)にジャンプする箇所があるのですが、なぜそんなことになるのか、いくら考えても分かりません。いろいろprintf()を埋め込んでいって、もうわけが分からなくなってしまいました。

該当のソースコード

C

1#include <stdio.h> 2#include <stdlib.h> 3 4#define N 10 5 6void qksort(int d[], int top, int end); 7 8int main(void) 9{ 10 int i; 11 int d[] = {11081, 5137, 24671, 5233, 26229, 12 14891, 25719, 11578, 5160, 4907}; 13 14 printf("【整列前】\n"); 15 for (i = 0; i < N; i++) 16 printf("%d ", d[i]); 17 printf("\n"); 18 19 qksort(d, 0, N - 1); 20 21 printf("【整列後】\n"); 22 for (i = 0; i < N; i++) 23 printf("%d ", d[i]); 24 printf("\n"); 25 return EXIT_SUCCESS; 26} 27 28void qksort(int d[], int top, int end) 29{ 30 int key, wk, i, j; 31 int k; /* デバッグ用 */ 32 33 printf("(*1)\n"); /* デバッグ用 */ 34 key = d[(top+end)/2]; 35 printf("key = %d\n", key); /* デバッグ用 */ 36 i = top - 1; 37 j = end + 1; 38 while (1) { 39 printf("(*2)\n"); /* デバッグ用 */ 40 while (d[++i] < key) 41 ; 42 printf("i = %d\n", i); /* デバッグ用 */ 43 while (d[--j] > key) 44 ; 45 printf("j = %d\n", j); /* デバッグ用 */ 46 if (i >= j) 47 break; 48 wk = d[i]; 49 d[i] = d[j]; 50 d[j] = wk; 51 for (k = 0; k < N; k++) /* デバッグ用 */ 52 printf(" %d", d[k]); /* デバッグ用 */ 53 printf("\n\n"); /* デバッグ用 */ 54 } 55 printf("(*3)\n"); /* デバッグ用 */ 56 printf("top = %d, i-1 = %d\n", top, i-1); /* デバッグ用 */ 57 printf("(*4)\n"); /* デバッグ用 */ 58 if (top < i-1) { 59 printf("(*5)\n"); /* デバッグ用 */ 60 printf("qksort(d, %d, %d);\n", top, i-1); /* デバッグ用 */ 61 qksort(d, top, i - 1); /* 左半分をクイックソート */ 62 } 63 printf("(*6)\n"); /* デバッグ用 */ 64 printf("j+1 = %d, end = %d\n", j+1, end); /* デバッグ用 */ 65 printf("(*7)\n"); /* デバッグ用 */ 66 if (j+1 < end) { 67 printf("(*8)\n"); /* デバッグ用 */ 68 printf("qksort(d, %d, %d);\n", j+1, end); /* デバッグ用 */ 69 qksort(d, j + 1, end); /* 右半分をクイックソート */ 70 } 71 printf("(*9)\n"); /* デバッグ用 */ 72 printf("(*10)\n"); /* デバッグ用 */ 73}

試したこと

すでに上のソースコードに埋め込んでありますが、printf()を使って実行の流れを可視化させました。その実行結果を、下に示します。

(実行結果)

【整列前】 11081 5137 24671 5233 26229 14891 25719 11578 5160 4907 (*1) key = 26229 (*2) i = 4 j = 9 11081 5137 24671 5233 4907 14891 25719 11578 5160 26229 (*2) i = 9 j = 8 (*3) top = 0, i-1 = 8 (*4) (*5) qksort(d, 0, 8); (*1) key = 4907 (*2) i = 0 j = 4 4907 5137 24671 5233 11081 14891 25719 11578 5160 26229 (*2) i = 1 j = 0 (*3) top = 0, i-1 = 0 (*4) (*6) j+1 = 1, end = 8 (*7) (*8) qksort(d, 1, 8); (*1) key = 11081 (*2) i = 2 j = 8 4907 5137 5160 5233 11081 14891 25719 11578 24671 26229 (*2) i = 4 j = 4 (*3) top = 1, i-1 = 3 (*4) (*5) qksort(d, 1, 3); (*1) key = 5160 (*2) i = 2 j = 2 (*3) top = 1, i-1 = 1 (*4) (*6) j+1 = 3, end = 3 (*7) (*9) (*10) (*6) j+1 = 5, end = 8 (*7) (*8) qksort(d, 5, 8); (*1) key = 25719 (*2) i = 6 j = 8 4907 5137 5160 5233 11081 14891 24671 11578 25719 26229 (*2) i = 8 j = 7 (*3) top = 5, i-1 = 7 (*4) (*5) qksort(d, 5, 7); (*1) key = 24671 (*2) i = 6 j = 7 4907 5137 5160 5233 11081 14891 11578 24671 25719 26229 (*2) i = 7 j = 6 (*3) top = 5, i-1 = 6 (*4) (*5) qksort(d, 5, 6); (*1) key = 14891 (*2) i = 5 j = 6 4907 5137 5160 5233 11081 11578 14891 24671 25719 26229 (*2) i = 6 j = 5 (*3) top = 5, i-1 = 5 (*4) (*6) j+1 = 6, end = 6 (*7) (*9) (*10) (*6) j+1 = 7, end = 7 (*7) (*9) (*10) (*6) j+1 = 8, end = 8 (*7) (*9) (*10) (*9) (*10) (*9) (*10) (*6) j+1 = 9, end = 9 (*7) (*9) (*10) 【整列後】 4907 5137 5160 5233 11081 11578 14891 24671 25719 26229

補足情報(FW/ツールのバージョンなど)

OSはWindows10、コンパイラはVisual Studio2012です。

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

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

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

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

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

guest

回答3

0

ベストアンサー

再帰してるんだから、呼び出した関数が終了(*10を出力)したら、呼び出し元に戻って、関数qsort呼び出し直後の処理(6や9の出力)をしますよ。

投稿2021/09/09 15:40

編集2021/09/09 15:41
kairi003

総合スコア1332

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

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

sanshirou

2021/09/09 16:21

あ、そうですね(照れ笑い)…。奥歯に挟まった物が取れたように爽快です。ありがとうございました。
guest

0

printf の入れ方が混乱の原因と思います。
流れを追うのでしたら、関数の始まりと終わり(この場合でしたら1と10)の対応をハッキリさせないと、いつ何の処理が始まり・終わったのかの区別がつきません。

良くあるのは、関数に入ったら entryやstart、出るときはreturnやendという文字列と共に、引数を表示するものです。(呼ぶ側ではなく呼ばれる側で表示します。)

c

1void qksort() 2{ 3 printf("qksort entry. top=%d, end=%d¥n", top, end); 4 5() 6 7 printf("qksort return. top=%d, end=%d¥n", top, end); 8}

もちろん return する場所が複数あれば全てに return の表示を入れ、それぞれにそれこそ番号等固有の文字列を付けます。
このようにすれば、少しは混乱を減らせるのではないでしょうか。

投稿2021/09/09 18:18

編集2021/09/09 18:23
jimbe

総合スコア13209

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

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

0

参考までに再帰関数の呼び出しを図示してみました。
「└→」が qksort 関数の開始
「←┘」が qksort 関数の終了
になります。

└→ └→ (*6) └→ └→ (*6) (*9) (*10) ←┘ (*6) └→ └→ └→ (*6) (*9) (*10) ←┘ (*6) (*9) (*10) ←┘ (*6) (*9) (*10) ←┘ (*9) (*10) ←┘ (*9) (*10) ←┘ (*6) (*9) (*10) ←┘

投稿2021/09/09 16:13

cx20

総合スコア4648

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

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

sanshirou

2021/09/09 16:23

ご親切に、ありがとうございました。自分で書けるようによく理解しておきます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問