• ベストアンサー

C言語の質問です

以下のコードは100個までの数値を受け取り、ソートするプログラムです。 #include <stdio.h> int main(void) { int item[100]; int a, b, t; int count; /* 数値を読み込む */ printf("数をいくつ入力しますか? "); scanf("%d", &count); for(a=0; a<count; a++) scanf("%d", &item[a]); /* ここでバブルソートを使用して数値を整列させる */ for(a=1; a<count; ++a) for(b=count-1; b>=a; --b) { /* 隣接する要素を比較する */ if(item[b-1] > item[b]) { /* 要素を交換する */ t = item[b-1]; item[b-1] = item[b]; item[b] = t; } } /* 整列後のリストを表示する */ for(t=0; t<count; t++) printf("%d ", item[t]); return 0; } バブルソートする部分が分かりません。 比較、交換するコードは分かるのですが… どなたか詳しく教えていただけないでしょうか?

質問者が選んだベストアンサー

  • ベストアンサー
  • chie65536
  • ベストアンサー率41% (2512/6032)
回答No.3

>バブルソートする部分が分かりません。 for(a=1; a<count; ++a) の1回目のループでは、aは1です。従って for(b=count-1; b>=a; --b) { のbは「最後の要素から、a(つまり1、先頭の1つ手前)になるまで」回ります。 1回目は「最後の要素と、最後の一つ手前の要素を比べ、最後の要素の方が小さいなら前に入れ替え」します。 そして、2回目は「最後の一つ手前の要素と、最後の二つ手前の要素を比べ、最後の一つ手前の要素の方が小さいなら前に入れ替え」します。 最後は「先頭の要素と、先頭の一つ次の要素を比べ、先頭の一つ次の要素の方が小さいなら前に入れ替え」します。 for(b=count-1; b>=a; --b) { のループが終ると「配列の先頭に、1番小さな値」が来ます。 そして for(a=1; a<count; ++a) のループが「aが2になって」繰り返すので「先頭を除外した、2番目から最後まで」で「同じ事」をします。つまり「配列の2番目に、2番目に小さな値」が来ます。 これを「最後の一つ手前と、最後の2個を比べるまで」繰り返すと、すべてがソートされて終了します。

Guchiken
質問者

お礼

回答ありがとうございます! インクリメントがa++、b--ではなく、++a、--bになっているのは どういう意図があるんでしょうか? よろしければ教えてください!

その他の回答 (6)

  • chie65536
  • ベストアンサー率41% (2512/6032)
回答No.7

蛇足ですが。 後置演算子と前置演算子のどっちを使うかで、最も気になるのは「インテル80386系CPUでポインタを使った時」です(つまり、昔で言うDOS/V機、今で言うWindows-PCをターゲットにした時) インテル80386系CPUは、ストリング操作命令と言う「ストリング操作した後に自動でアドレスを増減する」と言う命令を持っています(ストリング操作命令については、以下のページを参照) http://hp.vector.co.jp/authors/VA014520/asmhsp/chap6.html つまり、  *dst++ = *src++; や  *dst-- = *src--; が、機械語の1命令で済んでしまうのです。 しかし、この機械語命令は「操作した後に自動でアドレスを増減する」のですから「後置演算子」に相当します。言い換えれば「後置演算子だけサポートしている」のです。 つまり「前置演算子を使うと、便利な機械語命令があるのに、それが使われない場合がある」のです(言い換えれば「高速な命令が使われず、実行速度が落ちてしまう場合がある」と言うこと) ですので、インテル80386系CPUをターゲットにプログラミングする際「前置演算子で書けば判りやすいのに、あえて前処理を追加して、ポインタ操作は後置演算子だけで書く」なんて事をしたりします。 >今まで(使っている本の勉強している所までで)、後置演算子だったのが、 >いきなり前置演算子になったんで 上記のような理由もあって「前置演算子は滅多に使わず、後置演算子を頻繁に使う」と言う流れがあります。参考書の書き手もその流れで、殆どを後置演算子で説明してしまっているのでしょうね。

Guchiken
質問者

お礼

三度の回答ありがとうございます。勉強になります! chie65536 さんは"専門家"でも良いような気がするのですが… また、質問していたら、回答してやってください。 蛇足ぶんも含めて、三度の回答本当にありがとうございました。

  • chie65536
  • ベストアンサー率41% (2512/6032)
回答No.6

>インクリメントがa++、b--ではなく、++a、--bになっているのは >どういう意図があるんでしょうか? 「結果は同じ」ですが「無駄なコード生成を省き、最適化しやすくする」意味があります(但し、処理系に依存する) 「++a」と書いた場合、この「式の値」は「インクリメント後のa」になります。 「a++」と書いた場合、この「式の値」は「インクリメント前のa」になります。 ある処理系で「式の計算結果は、0番レジスタに求める」と決められていたと仮定します。 ++aは  inc.l [a]  ;aをlongサイズでインクリメント  move.l [a],r0  ;インクリメント後のaをr0レジスタにロード と言うコードが生成されるでしょう(命令コードは、説明用の仮想コード) a++は  move.l [a],r0  ;インクリメント前のaをr0レジスタにロード  inc.l [a]  ;aをlongサイズでインクリメント と言うコードが生成されるでしょう(命令コードは、説明用の仮想コード) ここまでは「命令コードの順序が違うだけ」で、速度的に何も変わりません。しかし、この後に「forループの条件比較と分岐」が行われます。 そのコードは、以下のようになるでしょう。  move.l [a],r0  ;aをr0レジスタにロード  comp.l [count],r0  ;r0(a)レジスタとcountを比較  jl forloop1  ;r0(a)が小さければループの最初へジャンプ これを、先ほどのインクリメント文と並べてみましょう。 ++aの場合  inc.l [a]  move.l [a],r0  move.l [a],r0  comp.l [count],r0  jl forloop1 a++の場合  move.l [a],r0  inc.l [a]  move.l [a],r0  comp.l [count],r0  jl forloop1 お気付きのように、前者の「++a」では、同一の命令コード「move.l [a],r0」が2つ続きます。 コンパイラのオプティマイザ(コード最適化)の性能が低いとしても、(副作用のない)同一の命令コードが2つ続いたなら1つにするくらいはやってくれる筈です。 ++aの場合、最終的には、以下のような4命令のコードになります。  inc.l [a]  move.l [a],r0  comp.l [count],r0  jl forloop1 しかし、a++の場合、オプティマイザの性能が悪いと、以下のように無駄な命令コードが1つ残ります。  move.l [a],r0  inc.l [a]  move.l [a],r0  comp.l [count],r0  jl forloop1 このように「熟練したCプログラマは、生成される機械語コードを予測しながら、複数の記述方法の中から最短最速になるだろう記述を瞬時に選んで、最適なソースコードを書ける」のです。 この「差」は「コンパイルオプションでオプティマイズ(最適化)をオフにしてコンパイルしてみる」と、ハッキリと実行速度の差として表面化します。けっして「書き手の好みの話」だけでは済まないのです。 とは言え、最近のコンパイラのオプティマイザはとても高性能で、命令コードの順序を入れ替えたり、CPUのパイプラインを考慮したりして「最適コード」を生成するので、プログラマが「どんな機械語コードが生成されるか」を気にする必要が無くなっています。

Guchiken
質問者

お礼

丁寧な回答ありがとうございます! やはり、意図するものがあったんですね! 今まで(使っている本の勉強している所までで)、後置演算子だったのが、 いきなり前置演算子になったんで、おかしいなと思っていたんです! これで、謎が解けました!安心して次のページに進めそうです!! 回答ほんとうにありがとうございました!

  • asuncion
  • ベストアンサー率33% (2126/6286)
回答No.5

> インクリメントがa++、b--ではなく、++a、--bになっているのは > どういう意図があるんでしょうか? 今回のプログラムでは、どちらでも同じです。 書き手の好みの話でありましょう。

Guchiken
質問者

お礼

回答ありがとうございます! 書き手の好みですか…。なぜ、前置演算子を使ったのか疑問でしたけど、 asuncion さんの回答で、気にせずにいこうと思うようになりました。 回答ありがとうございました。

  • gjgjhono
  • ベストアンサー率50% (1/2)
回答No.4

++a; と a++; の違いですが、以下のような感じです。 < ++aの例 > int a=0; int kai=0; kai = ++a; printf("a=%d kai=%d",a,kai); ------------------ a=1 kai=1 ------------------ < a++の例 > int a=0; int kai=0; kai = a++; printf("a=%d kai=%d",a,kai); ------------------ a=1 kai=0 ------------------ つまり ++が前にあると a=a+1を実行した後にkai=aを実行 ++が後にあると kai=aを実行した後にa=a+1を実行 といった感じになります。 上記を参考にされればよいかと思います。

Guchiken
質問者

お礼

回答ありがとうございます!! 後置演算子と前置演算子の違いは分かります。 でも、ここで前置演算子を使う意味がわかりません。 for文のインクリメント(デクリメント)部だから、 結局、前置も後置も一緒な気がするのですが…

  • php504
  • ベストアンサー率42% (926/2160)
回答No.2

間違えた 1ループ目 9,2,7,4,0 9,2,7,0,4 9,2,0,7,4 9,0,2,7,4 0,9,2,7,4 2ループ目 0,9,2,7,4 0,9,2,4,7 0,9,2,4,7 0,2,9,4,7 3ループ目 0,2,9,4,7 0,2,9,4,7 0,2,4,9,7 4ループ目 0,2,4,9,7 0,2,4,7,9 終了

Guchiken
質問者

お礼

回答ありがとうございます! 隣接する要素を比較して、交換するというのは想像できました。 しかし、バブルソート部分の2つのfor文がなぜそうなるのかわかりません。 また、a++、b--ではなくて++a、--bなのも分かりません。

  • php504
  • ベストアンサー率42% (926/2160)
回答No.1

具体例で雰囲気でも 1ループ目 9,2,7,4,0 9,2,7,0,4 9,2,0,7,4 9,0,2,7,4 0,9,2,7,4 2ループ目 0,9,2,7,4 0,9,2,4,7 0,9,2,4,7 0,2,9,4,7 0,2,9,4,7 3ループ目 0,2,9,4,7 0,2,9,4,7 0,2,4,9,7 0,2,4,9,7 0,2,4,9,7 4ループ目 0,2,4,9,7 0,2,4,7,9 0,2,4,7,9 0,2,4,7,9 0,2,4,7,9 終了

関連するQ&A

  • C言語初心者です。

    #include <stdio.h> int main() { int b[100]; int i, n; int a, r, data; int count=0; printf("Please input two integers:"); fflush(0); scanf("%d %d", &a, &r); if(a<=0 || r<=1){ printf("Error\n"); } else{ for(n=0; b[n]<=80.0; n++){ if(n==0){ b[0]=0; count++; } else { for(i=0; i<=n-1; i++){ data*=r; } b[n]=a*data; printf("%d ", b[n]); count++; } } printf("\n"); for(; count>0; count--){ printf("%d ", b[count]); } } return 0; } windows8でeclipseを使ってC言語を書いてます。 eclipse上だと何もエラーが表示されてないのですが、実行し、 Please input two integers: と表示された後、適当な数字2つを入力しても何も反応しません。 稚拙な質問ですいません。どなたか原因を教えてください。

  • c言語で分からないところがあるので教えてください。

    http://www9.plala.or.jp/sgwr-t/c/Q/ens06-61.html の問題がわかりません。 回答の #include <stdio.h> int main( void ) { int kekka[51]; int a, b, i; int amari; printf( "整数値を2つ入力してください " ); scanf( "%d%d", &a, &b ); if( b == 0 ){ printf( "処理終了\n" ); return 0; } printf( "%d / %d = ", a, b ); kekka[0] = a/b; for ( i = 1; i < 51;i++ ) { amari = a%b; if ( amari == 0 ) break; a = amari * 10; kekka[i] = a/b; } printf( "%d.", kekka[0] ); ここまでの部分はわかったのですが、 下の for ( a = 1; a < i; a++ ) { printf( "%d", kekka[a] ); } の部分がわかりません。 この部分は何を表わしているのか 教えてください。

  • C言語 ソートについて

    #include <stdio.h> #include <stdbool.h> #define NUM_ARRAY 4 #define NUM_DATA 5 int count_swap = 0; // 交換回数 int count_comparison = 0; // 比較回数 void selection_sort(int a[], int n) { } int main(void) { int data[NUM_ARRAY][NUM_DATA] = {{9, 7, 5, 6, 8}, {9, 8, 7, 6, 5}, {5, 6, 7, 8, 9}, {5, 6, 8, 7, 9}}; for (int i = 0; i < NUM_ARRAY; i++) { count_swap = 0; count_comparison = 0; int d[NUM_DATA]; copy_array(data[i], d, NUM_DATA); // 配列のコピー printf("----------------\n"); print_array(d, NUM_DATA); // ソート前の配列の表示 selection_sort(d, NUM_DATA); // 挿入ソートの実行 print_array(d, NUM_DATA); // ソート後の配列の表示 printf("比較回数: %d\n", count_comparison); // 比較回数の表示 printf("交換回数: %d\n", count_swap); // 交換回数の表示 } } 上の雛形を使って選択ソートを実行するという問題なのですが途中までそれっぽいのは出来たのですが上手くいかないので解答をお願いします。 下に自分が今書いているものを置いておきます。 #include <stdbool.h> #include <stdio.h> #define NUM_ARRAY 4 #define NUM_DATA 5 int count_swap = 0; int count_comparison = 0; void swap(int d[], int i, int j) { count_swap += 1; printf("swap a[%d] = %d, a[%d] = %d\n", i, d[i], j, d[j]); int temp = d[i]; d[i] = d[j]; d[j] = temp; } void copy_array(int *a, int *b, int n) { for (int i = 0; i < n; i++) { b[i] = a[i]; } } void print_array(int d[], int n) { for (int i = 0; i < n; i++) { printf("%d ", d[i]); } printf("\n"); } bool compare(int d[], int i, int j) { count_comparison += 1; printf("compare a[%d] = %d, a[%d] = %d\n", i, d[i], j, d[j]); if (d[i] > d[j]) { return true; } else { return false; } } void selection_sort(int d[], int n) { int min; for (int i = 0; i < n - 1; i++) { min = i; for (int j = i + 1; j < i; j++) { if (compare(d, min, j)) { min = j; } } swap(d, i, min); print_array(d, n); } } int main(void) { int data[NUM_ARRAY][NUM_DATA] = { {9, 7, 5, 6, 8}, {9, 8, 7, 6, 5}, {5, 6, 7, 8, 9}, {5, 6, 8, 7, 9}}; for (int i = 0; i < NUM_ARRAY; i++) { count_swap = 0; count_comparison = 0; int d[NUM_DATA]; copy_array(data[i], d, NUM_DATA); // 配列のコピー printf("----------------\n"); print_array(d, NUM_DATA); // ソート前の配列の表⽰ selection_sort(d, NUM_DATA); // 挿⼊ソートの実⾏ print_array(d, NUM_DATA); // ソート後の配列の表⽰ printf("⽐較回数: %d\n", count_comparison); // ⽐較回数の表⽰ printf("交換回数: %d\n", count_swap); // 交換回数の表⽰ } }

  • C言語

    このプログラムを作りたいのですが… ??????????? 物の総数を入れてください:12 取り出す物の数を入れてください:2 12個の異なる物から2個をを取り出す組み合わせの数は66です ?????????????? ここに出てくる数字は scanfで入れます。 だいたい こんな感じだと思うのですが… ***********の部分が わかりません。 ??????????????? #include<stdio.h> int factorial(int m,int r) { ************** } int main(void) {int a,b; printf("物の総数を入れてください:") scanf("%d",&a); printf("取り出す物の数を入れてください:") scanf("%d",&b); printf("12個の異なる物から2個を取り出す組み合わせの数は%dです。\n",a,b,factorial(a,b));) ?????????????? お願いします(>_<)

  • C言語の質問です

    #include <stdio.h> int main(void) { int stats[20], i, j; int mode, count, oldcount, oldmode; printf("20個の数字を入力してください: \n"); for(i=0; i<20; i++) scanf("%d", &stats[i]); oldcount = 0; /* モードを調べる */ for(i=0; i<20; i++) { mode = stats[i]; count = 1; /* この値の発生頻度を数える */ for(j=i+1; j<20; j++) if(mode==stats[j]) count++; /* 以前の数より多ければ、新しいモードを使用する */ if(count>oldcount) { oldmode = mode; oldcount = count; } } printf("モードは %d です\n", oldmode); return 0; } 上記のコードはユーザーに20個の数値を入力させ、 そのモード(最も頻繁に現れる数値)を調べて表示するプログラムです。 1番目のfor文までは分かります。そのあとが、どうしても分かりません!! 特に、oldcount = 0; とする所、count = 1; とする所、for文で j=i+1; とする所。 他、if文内が分かりません。 課題の丸投げではなく、本当に分からなくて困っています。 どなたか詳しく解説してくれないでしょうか?よろしくお願いします。

  • C言語の問題です!!

    すみません。 詳細表示をする際に、未ソート部の先頭要素の上に記号文字「*」を表示し、未ソート部の最小要素の上に記号文字「+」を表示したいと思い、以下のソースプログラムを作成したのですが、結果が何か違う気がします…。どこが違うのか、教えていただけませんか? また、プログラムを修正していただけませんか? #include<stdio.h> #include<stdlib.h> #include<time.h> #define swap(type,x,y) do{type t=x;x=y;y=t;}while(0) /*--- 単純選択ソート ---*/ void selection(int a[], int n) { int i, j,k,flg; char *disp[]={" ","[* ]","[ +]","[*+]"}; for (i = 0; i < n - 1; i++) { int min = i; for (j = i + 1; j < n; j++) { if (a[min] > a[j]) { min = j; } } for (k = 0; k < n; k++) { flg=0; if(k==i) flg|=1; if(k==min) flg|=2; printf("%s",disp[flg]); } printf("\n"); for (k = 0; k < n; k++) printf("[%2d]", a[k]); printf("\n"); swap(int, a[i], a[min]); } } int main(void) { int i, nx; int *x; printf("要素数 : "); scanf("%d", &nx); x = calloc(nx, sizeof(int)); srand(time(NULL)); for (i = 0; i < nx; i++) { x[i] = rand() % 100; printf("x[%d] = %d\n", i, x[i]); } selection(x, nx); for (i = 0; i < nx; i++) printf("x[%d] = %d\n", i, x[i]); free(x); return 0; }

  • C言語の質問です。

    #include"stdio.h" int main(void){ int a, b, add; scanf_s("%d%d", &a, &b); add = a+b; printf("add=%d\n", add); return 0; } と、------------------------------------------------------------------------------ #include"stdio.h" int tasizan(int x, int y); int main(void){ int a, b, add; scanf_s("%d%d", &a, &b); add = tasizan(a, b); printf("add=%d\n", add); return 0; } int tasizan(int x, int y){ int aa; aa = x + y; return aa; } の違いを教えてください。

  • c言語超初心者です。教えてください

    基本的だと思いますが教えてください。 #include <stdio.h> int main(void) { int na, nb: puts("二つの整数を入力してください."); printf("整数A:”); scanf("%d",&na); printf("整数B:”); scanf("%d",&nb); printf("それらの平均は%fです。\n,(na+nb)/2.0); return(0); } これでintの形で最後のprintfが%fなのですがintは%dとなるはずなのですがこれは2。0という実数値で割るから答えは実数値になりますよ。という意味で%fとしたのでしょうか?確かにこうしないと正しい値がでてこないのです。教えてください。

  • C言語のプログラミングについて質問です。

    以下の文を出力して入力:に16進数を入れると10進数に変換した数値の小さい列順に並ぶプログラムを作りたいのですがうまく出来ません。 仕様は以下に記載します。 入力:__、__、__、__、__EnterKeyで結果を表示。 以下のバブルソートの文のどこをいじれば良いでしょうか? 返答宜しくお願いします。 #include <stdio.h> int main (void) { char data[256]; int val[100]; int i = 0; int work; int j; int k; printf("入力 = "); scanf("%s",data); for(i=0;i<100;i++){ val[i] = 0; } k=0; for(i = 0;i<100 ; i++){ if(data[i] == 0x00){ //data[i]がNULLだったら処理を抜ける k++; break; //enterキーでprintf出力 } else if(data[i] == ','){ //カンマだったら /*printf("%d\n",k);*/ k++; } else{ if(data[i] >= 'A' && data[i] <= 'Z'){ //data[i]にAからZが入ったら val[k] = val[k] *16 + data[i] -'A'+10; } else if(data[i] >= '0' && data[i] <= '9'){ //data[i]に0から9が入ったら val[k] = val[k] *16 + data[i] -'0'; } } } /* printf("k=%d\n",k); for(i=0;i<k;i++){ printf("出力 = %d\n",val[i]); } */ //バブルソート//     for(i=0; i<k-1; i++) { if(val[i] < val[i+1]) { } else{ work = val[i]; val[i] = val[i+1]; val[i+1] = work; } } for(i=0;i<k;i++) { printf("出力 = %d\n",val[i]); } }

  • C言語について

    ソートを使い入力した数値を並び替える。昇順、降順を選べるようにする。 順位を付けるた。ただし、複数同位があった場合にはその個数分順位が変更する。 このような問題なのですが 入力個数の部分までは自力でできたのですが、ソートを習っていないのでこの後がよく分かりません。 下のような実行結果になるようだれかわかる人お願いします。 # include <stdio.h> int main(void) { int a[100],kai=0,sentaku; printf("整数を入力(CTRL+dで終了) >> "); while(1){ if(scanf("%d",&a{kai}) == EOF )break; kai=kai+1; printf("整数を入力(CTRL+dで終了) >> "); } printf("入力個数%d回\n",kai); return 0; } 実行結果 数値>>1 数値>>3 数値>>-1 数値>>-3 数値>>10 数値>>3 数値>> 入力回数:4回 1:昇順、2:降順>>1 NO.1:-3 NO.2:1 NO.3:3 NO.3:3 NO.5:10

専門家に質問してみよう