• ベストアンサー

文字の並べ替えについて質問

以下のような標準入力したアルファベットの文字列(jgoaihoghohgo...みたいな)を昇順に並べ替えるプログラムを作成して思ったのですが、各文字の比較ってやっぱりアスキーコードの数字を比較しているのでしょうか? だとするとif(s[i]<s[j])の部分で少し疑問を感じました。 if(s[i]>s[j])ではないのでしょうか?こうでないとs[i]にaがs[j]にbが格納されているときに並べ替えが起きてしまうような気がするのです。 基本的なことのようですがお願いしますm(__)m あとプログラムに関して不備を感じましたら訂正のアドバイスをお願いします。 #include<stdio.h> #include<string.h> int main(void){ char s[BUFSIZ]; char s2[BUFSIZ]; int i,j,m; printf("input sentense.\n"); scanf("%s",s); m=strlen(s); for(i=0;i<m;i++){ for(j=0;j<m;j++){ if(s[i]<s[j]){ s2[10]=s[i]; s[i]=s[j]; s[j]=s2[10]; } } } printf("%s",s); return(0); }

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

  • ベストアンサー
  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.1

>if(s[i]>s[j])ではないのでしょうか? 紙に書いて実際に動きをトレースしてみると判ると思いますが、 0<=i<m 0<=j<m でループするために、一回比較が終わったハズの部分がもう一回比較される時に逆になるのでこれでソートできるということだと思います。 つまり前半部で、いったん大きいモノが前に来るがそれが、もう一回交換されることで小さいモノが先にくるという。 例えば、 bca の並びの文字列があったとすると、 最初(iが0の時のループ) cbaになります。 ところが(iが1の時のループで) bca になります。 つまり、iで着目している部分より前にいったん大きいモノが集まり、そこを過ぎると小さいモノに置き換えられると言うことになると言うことだと思います。 >プログラムに関して不備を感じましたら訂正のアドバイス このソート自体は、同じペアについて2回比較されるので、ムダですよね。 あと、s2は、結局一文字しか使用していないので、一文字だけでよいと思います。 また、BUFSIZのサイズを知った上で使用してるのでしょうが、 BUFSIZは、コンパイラによって変わる可能性があるので、 そういう不定のサイズであるということから、 s2[10]のような使い方はよろしくないと思います。

you-two
質問者

お礼

今まで一回の比較で済むものと思ってました!! すんごい分かりやすかったです☆ ずっと思っていた疑問が解決できました! 文字列の使用の注意など感謝します。

その他の回答 (2)

回答No.3

まず、プログラムについてのコメントですが char s2[BUFSIZ]; ↓ char c; s2[10]=s[i]; s[i]=s[j]; s[j]=s2[10]; ↓ c=s[i]; s[i]=s[j]; s[j]=c; にしても動きますので、こちらの方が良いと思いますよ。 本題ですが、 ご存知のとおり、文字はアスキーコードで表しています。 ここで注目するところは、このプログラムのアルゴリズムです。 このアルゴリズムでは if( s[i] < s[j] ) が正解です。 これと似た書き方をするバブルソートというアルゴリズムがあります。 (これをやりたかったのかな^_^;) 参考までに記述しておきます。 for(i=0; i<m; i++) { for(j=i; j<m; j++) { if( s[i] > s[j] ) { c = s[i]; s[i] = s[j]; s[j] = c; } } } このアルゴリズムでは if( s[i] > s[j] ) と書きます。 これで、解決したでしょうか? アルゴリズムに関しては理解に苦しむかもしれませんが がんばってください(^_^)

you-two
質問者

お礼

アドバイス感謝です☆ 文字列と文字の使い方にも今まで疑問を持ってたんですが おかげで解決できました!! 文字ってこんな風に使うんですね~。勉強になりました。

  • mac_res
  • ベストアンサー率36% (568/1571)
回答No.2

BLUEPIXYさんの回答に加えて、scanf(3)はBuffer Over flowの危険があるので、fgets(3)にしたほうが良いでしょう。 -- 8< -- 8< -- 8< -- 8< -- 8< -- 8< -- 8< -- 8< -- 8< -- 8< -- 8< -- #include <stdio.h> #include <string.h> int main(void) { char s[BUFSIZ]; char c; int i, j, m; printf("input sentense.\n"); fgets(s, BUFSIZ, stdin); m = strlen(s); s[--m] = 0; for (i = 0; i < m; i++) { for (j = i; j < m; j++) { if (s[i] > s[j]) { c = s[i]; s[i] = s[j]; s[j] = c; } } } printf("%s\n", s); return (0); }

you-two
質問者

お礼

なるほどです!! これだとfor文で無駄なループがないっすね。 いや、マジで感謝します。 文字と文字列の違いが分かりやすく為になります~

関連するQ&A

  • 文字列中の空白部の読み込みの方法を教えてくださいm(_ _)m

    いつもお世話になっています!!キーボードから以下のような文字列を読み込み、大文字のみをカウントするプログラムを作りたいのですが、空白部になると次の文字を判定せずにプログラムが停止してしまいます。。。どなたかアドバイスをお願いしますm(_ _)m ○文字列 My name is Marly. ○プログラムソース #include<stdio.h> #include<stdlib.h> #include<string.h> int main(void){ char *s; int i,j=0,m; s=(char*)malloc(sizeof(char)); printf("please iput sentens\n"); scanf("%s",s); m=strlen(s); for(i=0;i<m;i++){ if( 0x41 <= s[i] && s[i] <= 0x5A) j++; } printf("%d",j); free(s); return(0); }

  • 文字の並べ替え

    C言語で文字の並べ替えをしたいのですが条件があり ポインタを使って文字を並べ替える別の関数をを渡さなければなりません.(void reverse(char *str)をつくる) そこで作ったのが #include <stdio.h> #include <string.h> void reverse(char *str); int main(void){ char s[80]; gets(s); reverse(s); printf("%s\n",s); return 0; } void reverse(char *str){ char q[80]; int i,n; n=strlen(str)-1; str+=n; for(i=0;i<=n;i++)q[i]=*str--; str++; q[i]='\0'; for(i=0;i<=n;i++)*str++=q[i]; } なのですが ポインタを使っている意味が余りないので ポインタを使うよりよいプログラムを教えてください. (アドバイスでもかまいません.)

  • 文字列とポインタの問題です。

    #include<stdio.h> int f(char *s); int main(void){ char*str="nasida Institute of Technology"; int i; i=f(str); printf("%s:%d\n",str,i); return 0; } int f(char *s) { int j=0; while(*s!='\0'){ if(*s=='t'){ j++; } s++; } return j; } このプログラムの答えが3になるんですが、if文のとこの動作がよく分からないので、よろしくお願いします。

  • かぶった文字を消すプログラム

    文字列s2中の任意の文字に等しい文字をs1から除外するプログラムを以下の様に作りましたが、ビルトと入力は出来るものの、出力が出ません。何が間違っているのでしょう? #include <stdio.h> main() { int i,j,c; char s[100],t[100]; for( i = 0; (c = getchar()) != '\n'; i++){ s[i] = c; } for( i = 0; ((c = getchar()) != '\n') && (c != EOF); i++){ t[i] = c; } for( i = 0; s[i] != '\0'; i++){ for( j=0; t[j] != '\0'; j++){ if( s[i] == t[j] ){ s[i] = ' '; } } } for( i = 0; s[i] != '\0'; ++i ){ printf("%s", s[i]); } }

  • 文字を逆転させて表示させるプログラミングなのですが・・・。

    #include<stdio.h> int main() { char moji[80]; char hantai[80]; int i; int j; int n; printf("半角文字列を入力:"); scanf("%s",moji); for(n=0;moji[n]!='\0';n++); for(i=n-1,j=0,i>=0;i++;j--){ hantai[j]=moji[i]; } hantai[j]='\0'; printf("反対から:%s\n",hantai); return 0; } 反対からが表示されません。 考えたのですがわかりません。

  • どこがちがうのでしょうか?

    以下の二つのプログラムはユーザーが文字を入力し、80文字以下なら ピリオドを追加して表示するというものです。上はうまくいきますが、下はうまくいきません。なぜでしょうか? #include<string.h> #include<stdlib.h> int main() { char str[80]; int i; printf("文字列を入力してください。\n"); gets(str); if(strlen(str)<80) { for(i=strlen(str);i<79;i++) strcat(str,"."); } printf("%s",str); } #include<stdio.h> #include<string.h> #include<stdlib.h> int main() { char str[80]; int i; printf("文字列を入力してください。\n"); gets(str); if(strlen(str)<80) { for(i=strlen(str)+1;i<79;i++) str[i] = "."; } printf("%s",str); }

  • 文字列をa→1b→2...z→26に変換する

    文字列を上記のように変換して表示するプログラムについて #include<stdio.h> int main() {    char ch[10];    printf("小文字のアルファベットの文字列を入力\n");    scanf("%s",&ch);    int i=0,j=97;    while(ch[i]!='\0'){      for(j; j<=97+26; j++){        if(ch[i]==j){          ch[i]=j-96;          printf("%d\n",ch[i]);        }      }    i++;    }    return 0; } 一文字の場合は問題ないのですが複数になるとうまくいきません 実行例 a 1 hello 8 となってしまいます。 改善をお願いします。

  • 配列とポインタを使って特定の文字だけ大文字にする

    配列とポインタを使って特定の文字だけ大文字にするプログラムを作りたいのですがどのように作ればいいのでしょうか? 例えば、sportsのsだけ判別してSportSというふうにしたいです。 一応以下のようなプログラムを作ったのですが、実行してもsportsのままで何も変わりません・・・。 #include<stdio.h> void mojihenkan(char *); main(void) { char moji[8]={"sports"}; char *p; int i; mojihenkan(moji); p=moji; for(i=0;i<8;i++){ printf("%c",*(p+i)); } return 0; } void mojihenkan(char *a) { int i; for(i=0;i<8;i++){ if(*(a+i)=='s'){ a-32; } } }

  • 文字列の並び替えについて。

    #include<stdio.h> #include<string.h> main() {char name[40][50]; int i; for(i=1;i<=;i++){ printf("名前="); gets(name[i]); } if(strcmp(name[1],name[2])>0){ printf("%s %s \n",name[2],name[1]);} if(strcmp(name[1],name[2])<0){ printf("%s %s \n",name[1],name[2]);} if(strcmp(name[1],name[2])==0){ printf("%s %s \n",name[1]);} } は二人の名前を早い順に並べ替えるものなんですが、これを五人の名前を並べ替えるものにしたいので、どのようなプログラムにしたらいいのか教えてください。

  • 変な動作をしてしまう

    月名の日本語を入力して英語にするプログラムなのですが、最後の 「間違えた月:」の結果がしっかり表示されません。 結果のどうこうに問わず、必ず「間違えた月:1月,1月,1月,1月, 1月,1月,4月,5月,」と表示されてしまうのです。 ちなみに、その上の「正解した月」はちゃんと思惑通りに 動作します。 このプログラムのどこがおかしいためにそのように表示されて しまうのでしょうか? よろしくお願いします。 #include<stdio.h> #include<time.h> #include<stdlib.h> #include<ctype.h> #include<string.h> #define swap(type,x,y) do{type t=x;x=y;y=t;}while(0) char *tukistr[]={"january","feburary","march","april","may","june","july", "augst","september","october","november","december"}; int main(void) { int nstr[12]={0,1,2,3,4,5,6,7,8,9,10,11}; char tuki[10]; int num; int seikai=0; int k=0; int seiho[12]; int huseiho[12]; int m=0; int i,j,p; char hen; srand(time(NULL)); printf("月名の英語を入力してください。入力は大文字でも小文字でも構いません。\n"); for(i=11;i>0;i--) { j=rand()%i; swap(int,nstr[j],nstr[i]); } for(i=0;i<12;i++) { printf("%d月 : ",nstr[i]+1); scanf("%s",tuki); do{ for(j=0;j<strlen(tukistr[nstr[i]]);j++) { hen=tolower(tuki[j]); if(hen!=tukistr[nstr[i]][j]) { printf("違います。正解を見ますか? 0-いいえ/1-はい:"); huseiho[m++]=nstr[i]; scanf("%d",&num); if(num==0) { printf("もう一度入力してください。:"); p=1; scanf("%s",tuki); j=0; } break; } } }while(num==0 && j<strlen(tukistr[nstr[i]])); if(j==strlen(tukistr[nstr[i]])) { printf("正解です。\n"); if(p!=1) { seikai++; seiho[k++]=nstr[i]; } p=0; } else if(num==1) { printf("%d月は%sです。\n",nstr[i]+1,tukistr[nstr[i]]); } } printf("12個のうち%d個が正解でした。\n",seikai); printf("正解した月:"); for(j=0;j<12;j++) { for(i=0;i<12;i++) { if(j==seiho[i]) { printf("%d月",j+1); if(j!=11) { printf(","); } } } } printf("\n\n"); printf("間違えた月:"); for(j=0;j<12;j++) { for(i=0;i<12;i++) { if(j==huseiho[i]) { printf("%d月",j+1); if(j!=11) { printf(","); } } } } return 0; }

専門家に質問してみよう