• ベストアンサー

選択ソートについて

------------------------------------- #include<stdio.h> int main(void) { int min,s,t,i,j; int num[]={5,6,4,9,2}; for(i=0;i<4;i++){ min=num[i]; s=i;        ////◎1 for(j=i+1;j<5;j++){ if(num[j]<min){ min=num[j]; s=j; } } t=num[i]; num[i]=num[s]; num[s]=t; } for(i=0;i<5;i++){ printf("%d ",num[i]); } putchar('\n'); return 0; } -------------------------------------- 以上のプログラムで◎1の記述が無くても正常にソートしてくれたので疑問に思いました。 「s=i;」が無い場合、最初のループのif文で、 if(num[j]<min){ min=num[j]; s=j; } 「6<5」を比べる時、条件に見合わないので、sに何も代入されず、 t=num[i]; num[i]=num[s]; num[s]=t; 以上の記述で、sが初期化されてないので、その時点のエラーが出ると思ったんですが、出ないで正常に動きました。 何故なのか教えてもらえると嬉しいです。

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

  • ベストアンサー
  • chie65535
  • ベストアンサー率43% (8517/19361)
回答No.4

>以上の記述で、sが初期化されてないので、その時点のエラーが出ると思ったんですが、出ないで正常に動きました。 「◎1の行が無い場合に、sに値が一度も代入されず、不定になる」のは「元々、データがソート済みの時」だけです。 「元々、データがソート済みの時」と言うのは、言い換えれば if(num[j]<min){ min=num[j]; s=j; } の部分を1度も通らない時、です。 ◎1が存在する理由は「元々、データがソート済みの時、 if(num[j]<min){ min=num[j]; s=j; } の部分を1度も通らないから t=num[i]; num[i]=num[s]; num[s]=t; を行っても、入れ替えをしないようにする為」です。 最初に s=i; とやっておけば、元々ソート済みの場合 t=num[i]; num[i]=num[s]; num[s]=t; の所に来た時にsとiが同じ値になっているので、入れ替えは起きません。 以下蛇足。 ANo.3の回答者さんへ >☆コーディングでは、「インデント」すべきです。 当サイトでは、質問文中、回答文中の「行頭の半角スペース」は、自動的にすべてカットされてしまいます。 なので、質問者さんが「インデント済みの、ちゃんとしたコーディングをしたソースコード」を質問文に貼り付けても、すべてのインデントが勝手に削除されてしまいます。 従って、質問者さん(や他の回答者さん)に対して「ソースコードをインデントしてない」と言う指摘をするのは正当でない可能性があります。 「当サイトでは、インデントは勝手に消えてしまう」と言うのを念頭に置いて、今後、C/C++などのカテゴリで回答する際は「インデントすべき」と言う指摘はしない方が良いです。 下手に指摘すると「いちいちウルサイな。こっちはちゃんとインデントしてあるのを貼ってる。勝手にインデント消えるんだから仕方ないだろ」と思われてしまい、相手に悪い印象を与えます。ご注意を。

muffler
質問者

お礼

ご回答ありがとうございます。 >「◎1の行が無い場合に、sに値が一度も代入されず、不定になる」の>は「元々、データがソート済みの時」だけです。 if文の条件が1度も適合しないという事で、上記の内容理解できました。ありがとうございます。

その他の回答 (4)

  • yama5140
  • ベストアンサー率54% (136/250)
回答No.5

No.3 です。 >2個目のfor文が範囲の分だけ繰り返し終わってから、 >t=num[i]; >num[i]=num[s]; >num[s]=t; >以上に進むという感じですよね?  はい、そうです。  「 for 構文がどこまでか」が判った、ということですね。  (構文中で、break; を用い、ループ途中で抜け出すことも可能です) >初心者なもので、すいません。  いえいえ、コーディングスタイル(インデント)云々より、「 for 構文の理解」でしたね。  後先となって、失礼しました。  今後は、コーディング時に適切にインデントしておけば、視覚的に把握できるかと・・。 No.4 さんへ >当サイトでは、質問文中、回答文中の「行頭の半角スペース」は、自動的にすべてカットされてしまいます。  存じていました(このため No.3 回答文中では、全角空白を用いています)。  連続する複数の半角スペースが1つになること、タブも・・。 >下手に指摘すると「いちいちウルサイな。こっちはちゃんとインデントしてあるのを貼ってる。勝手にインデント消えるんだから仕方ないだろ」と思われてしまい、相手に悪い印象を与えます。ご注意を。  上手にアドバイスしたい、と思っているのですがなかなか・・、ご注意ありがとうございます。

muffler
質問者

お礼

最初からソートされていた場合、sに値が代入されず動作が不安定になるという事も理解していなかったのですが、ご指摘通りfor文が多重になった場合の事が、完全に理解できてなかったです。 その後勉強し理解できました。ありがとうございます。

  • yama5140
  • ベストアンサー率54% (136/250)
回答No.3

>以上の記述で、s が初期化されてないので、その時点のエラーが出ると思ったんですが、出ないで正常に動きました。  いいえ、5より小さい4が現れた時点で、s に 2 が代入(「初期化」)されます。  そしてさらに、2で、s に 4 が代入されます。    最後の2まで比較してから、質問者様の言われる「その時点」に進みます。 先頭データが5でなく、1ですと質問者様期待どおりの結果となります(◆)。 +++++++++++++++++++++++++++++++++++++++++++++++ ☆コーディングでは、「インデント」すべきです。 始めから下のようにコーディングしていたら、今回の質問はなかったのではないでしょうか。   for( i = 0; i < 4; i++ ){     min = num[ i ];     s = i; // このステップがない場合(◆)     for( j = ( i + 1 ); j < 5; j++ ){       if( num[ j ] < min ){         min = num[ j ];         s = j;       }     }     t = num[ i ];     num[ i ] = num[ s ];  // 「その時点」     num[ s ] = t;   }

muffler
質問者

お礼

ご回答ありがとうございます。 2個目のfor文が範囲の分だけ繰り返し終わってから、 t=num[i]; num[i]=num[s]; num[s]=t; 以上に進むという感じですよね? 確かに、先頭を「1」にすると、i=0の時、if文の条件が1度も適合せず実行は出来ましたが、エラーを報告する、しないの画面が出てしまいました。 初心者なもので、すいません。

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

>if(num[j]<min){ >min=num[j]; >s=j; >} 上記の処理がfor文によるループの中に書いてあって、 1度だけ実行するわけではない(6<5の判定だけではない)ことに留意してください。

muffler
質問者

お礼

ご回答ありがとうございます。 まずi=0の時、 for(j=i+1;j<5;j++){ if(num[j]<min){ min=num[j]; s=j; } 上記を4回繰り返してから、以下を1回実行するという感じですかね? t=num[i]; num[i]=num[s]; num[s]=t; 初心者なもので、すいません。

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

int num[]={5,6,7,8,9}; のように最初からソートされている場合のみ s=j;が実行されません。 そして s=i; が無いとsに値が代入されなくなり動作が変になるでしょう。

muffler
質問者

お礼

ご回答ありがありがとうございます。 >最初からソートされている場合のみ s=j;が実行されません。 上記の内容納得出来ました。if文の条件に1度も合わないので、その結果動作が変になってしまうと分かりました。ありがとうございます。

関連するQ&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でアルゴリズムの勉強をしているものです。 以下のプログラムを実行して 9 8 7 6 5 4 3 2 1 10 入力すると 10 2 3 4 5 6 7 8 9 9 と帰ってきます。 習いたてでどこが悪いかわからないのでどなたか教えてください 汗。 ////*直接選択法*//// #include <stdio.h> #define MAXDATA 10 void selection(int a[],int n){ int i,j,t; for(i=0 ; i < n ; i++){ for(j=i+1 ; j<n ; j++){ if(a[j] < a[i]) t = a[i]; a[i] = a[j]; a[j] = t; } } } int main(void) { int k,j,sort[MAXDATA]; for(k=0;k < MAXDATA;k++) {printf("sort[%d]:",k); scanf("%d",&sort[k]);} for(k=0;k < MAXDATA;k++) printf("%3d",sort[k]); puts("ソートしますか? Yes:1 No:0 ///"); scanf("%d",&j); if(j==1){ selection(sort,MAXDATA); for(k=0;k < MAXDATA;k++) printf("%3d",sort[k]); } putchar('\n'); return(0); }

  • ソートプログラム

    前に質問したものです。慌てていたのですみません。 Cで書いた直接選択法です。 #include <stdio.h> #include <stdlib.h> #include <time.h> #define N 1000 void main( void ) { int min,s,t,i,j,k,a[N]; srand((unsigned int)time(NULL)); for(i=0;i<N;i++) a[i]=rand()%1000+1; for(j=0;j<i-1;j++){ min=a[j]; s=j; for(k=j+1;k<i;k++){ if(a[k]<min){ min=a[k]; s=k; } } t=a[j];a[j]=a[s];a[s]=t; for(s=0;s<i;s++) printf("%d,\t",a[s]); } } このプログラムを実行すると、1回ずつ入れ替えされたものが出力されます。 100回、200回、・・・と入れ替えを行った値を出力するには、どうすればよいでしょうか? ループを入れてみたりしてみましたが、、?? プログラムを再帰の方法をつかって書いたほうが、、、?? よろしくお願いします。

  • マージソート内の再帰処理にすいて

    #include<stdio.h> #define MAX 4 int temp[MAX]; void marge(int num[],int left,int right) { int i,j,mid,k   if(left>=right)return; mid=(left+right)/2; marge(num,left,mid);//(1) maege(num,mid+1,right);//(2) for(i=left;i<=mid;i++) temp[i]=num[i]; for(i=mid+1,j=right;i<=right;i++,j--) temp[i]=num]j]; i=left; j=right; for(k=left;k<=right;k++) if(temp[i]<=temp[j]) num[k]=temp[i++]; else num[k]=temp[j--] } マージソート内はこういった関数を記述してエラーもでないのですが、(1)と(2)の処理がよくわかりません。 (1)は再帰的に処理していってif(left>=right)return;の条件を満たした場合に(2)の処理に入っていきますよね? その場合、(2)の処理を行う際に(1)が(2)の再帰より前に記述されているので(1)がまた処理されるのでしょうか? 一連の流れを(1)、(2)を使って表してほしいです。

  • 基準値をランダムに選んでの選択ソート

    配列要素から基準値(pivot)をランダムに選び、K番目に小さい要素を検索するプログラムを書いているのですが、うまくいきません。かなり考えているのですが、何が間違っているのか全然わかりません。どなたか教えていただけないでしょうか? #include<stdio.h> #include<stdlib.h> #include<time.h> int pivotpoint; void partition3(int *s,int low,int high,int *pivotpoint) { int i,j,randspot; int tmp; int pivotitem; randspot=rand()%(high+1); pivotitem=s[randspot]; j=low; for(i=low+1;i<=high;i++){ if(s[i]<pivotitem){ j++; tmp=s[i]; s[i]=s[j]; s[j]=tmp; } } *pivotpoint=j; tmp=s[low]; s[low]=s[*pivotpoint]; s[*pivotpoint]=tmp; } int selection3(int *s,int low,int high,int k) { if(low==high) return s[low]; else{ partition3(s,low,high,&pivotpoint); if(k==pivotpoint) return s[pivotpoint]; else if(k<pivotpoint) return selection3(s,low,pivotpoint-1,k); else return selection3(s,pivotpoint+1,high,k); } } main() { int num,i,k; int high; int low=0; int s[1000]; struct timeval t1,t2; int seed=2; printf("How many elements?:"); scanf("%d",&high); printf("?n"); printf("What is the kth smallest number?:"); scanf("%d",&k); printf("?n"); srand(seed); for(i=0;i<high;i++){ s[i]=rand(); printf("%d ",s[i]); } printf("?n"); gettimeofday(&t1,0); num=selection3(s,low,high-1,k-1); gettimeofday(&t2,0); printf("Time=%dmicrosec?n", t2.tv_usec-t1.tv_usec); printf("The %dth smallest is %d?n ", k,num); }

  • 選択法(selection sort)について

    選択法について質問させていただきます。 選択法で基準値(pivot)を使用し、K番目に小さい要素を見つけるプログラムを作成しています。以下は私が作成したプログラムですが、 行き詰まってしまいました。どなたか教えていただけないでしょうか?ちなみに学校の宿題で引数は変えれない状態です。 #include<stdio.h> int selection(int low,int high,int k){ int pivotpoint; int s[]={27,10,12,20,25,13,15,22}; if(low==high) return s[low]; else{ partition(low,high,pivotpoint); if(k==pivotpoint) return s[pivotpoint]; else if(k<pivotpoint) return selection(low,pivotpoint-1,k); else return selection(pivotpoint+1,high, k); } } void partition(int low,int high,int pivotpoint){ int i,j; int pivotitem; int tmp; int s[]={27,10,12,20,25,13,15,22}; pivotitem=s[low]; j=low; for(i=low+1;i<=high;i++){ if(s[i]<pivotitem){ j++; tmp=s[i]; s[i]=s[j]; s[j]=tmp; } } pivotpoint=j; tmp=s[low]; s[pivotpoint]=s[low]; s[low]=tmp; } main(){ int num; int s[]={27,10,12,20,25,13,15,22}; num=selection(0,7,3); printf("the third number is %d?n", num); } エラーメッセージ selection.c:20: error: conflicting types for 'partition' selection.c:10: error: previous implicit declaration of 'partition' was here

  • 教えてください

    このソースのbunpu[tensu[i] / 10]++;がよく分からないので詳しく教えてください。 あと、 printf(" 100:"); for(j=0; j < bunpu[10]; j++) putchar('*'); putchar('\n');についても何を示しているのかわかりません。そこも詳しく教えてください。宜しくお願いします。 #include <stdio.h> #define NUMBER 80 int main(void) { int i, j; int num; int tensu[NUMBER]; int bunpu[11] = {0}; printf("人数を入力してください:"); do{ scanf("%d", &num); if(num < 1 || num > NUMBER) printf("\a要 [1以上%d以下] :", NUMBER); }while (num < 1 || num > NUMBER); puts("点数を入力してください。"); for(i=0; i < num; i++) { printf("%2d番:", i+1); do{ scanf("%d", &tensu[i]); if (tensu[i] < 0 || tensu[i] > 100) printf("\a要 [0以上100以下] :"); }while (tensu[i] < 0 || tensu[i] > 100); bunpu[tensu[i] / 10]++; } puts("\n 分布グラフ "); printf(" 100:"); for(j=0; j < bunpu[10]; j++) putchar('*'); putchar('\n'); for (i=9; i >=0; i--) { printf("%3d-%3d:", i*10, i*10+9); for (j =0; j < bunpu[i]; j++) putchar('*'); putchar('\n'); } return(0); }

  • 小さい順に並べ替えるプログラム

    コンピュータに10個のてきとうな数字を入力させ それを、小さい順に並べ替えるプログラムです。 以下のようにしたのですが、エラー0 警告0 なのに動きません。 どこが違うのでしょうか? #include<iostream> #include<cstdlib> #include<ctime> using namespace std; const int NUM_ELEMENTS=10; void sort(int*); void generation(int*); void exchange(int&,int&); void sort(int* a){ int min, locate, i, j; for(i=0; i<NUM_ELEMENTS-1; i++){ min = a[i]; locate = i; for(j=i; j<NUM_ELEMENTS; j++){ if(min > a[j]){ min = a[j]; locate = j; } } exchange(a[i],a[locate]); } } void generation(int* a){ int i; srand(time(NULL)); for(i=0; i<NUM_ELEMENTS; i++){ a[i] = rand(); } } void exchange(int& a,int& b){ int t; t=a; a=b; b=t; } int main(){ int data[NUM_ELEMENTS]; generation(data); sort(data); return 0; }

  • ややこしいコード

    #include<iostream> using namespace std; int main() { const int num = 5; int test[num]; cout << num << "人の点数を入力して下さい。\n"; for (int i = 0; i < num; i++) { cin >> test[i]; } for (int s= 0; s < num - 1; s++) { for (int t = s + 1; t < num; t++) { if (test[t] > test[s]) { int tmp = test[t]; test[t] = test[s]; test[s] = tmp; } } } for (int j = 0; j < num; j++) { cout << j + 1 << "番目の人の点数は" << test[j] << "です。\n"; } return 0; } 配列を並べ替える(ソート)する練習コードなんですが、 ちょっとややこしいので解りやすく教えて欲しいです。 因みに点数は、 22,80,57,60,50の順でお願いします。

  • 最大値と最小値を表示したいのですが・・・

    double numに入っている数字から最大値と最小値を求めたいのですが、このままだと両方とも1.000になってしまうんです・・・ どうやったらちゃんと最大値と最小値が表示されるのでしょうか?? 初心者なものでスイマセンが教えてください!! #include<stdio.h> int main(void) { int i,j; double num[]={4.5,3.1,7.0,9.2,1.0,5.7,9.3,2.3,0.3,1.0}; double max,min; for(i=0; i<10; i++) { for(j=0; j<10; j++) { if(num[i]>num[j]) max=num[i]; } } for(i=0; i<10; i++) { for(j=0; j<10; j++) { if(num[i]<num[j]) min=num[i]; } } printf("最大値は%fです。",max); printf("最小値は%fです。",min); return 0; }

専門家に質問してみよう