• 締切済み

Ruby バブルソート

バブルソートのプログラムでわからないところがあるため、 質問させていただきます。 Rubyは1.9.3を使用しています。 <プログラム> --------------------------------------------------- def bsort(data)   while true     # swapped変数は数値の入れ替えを記憶     swapped = false     for i in 0..data.size-2       if data[i] > data[i+1]         temp = data[i]         data[i] = data[i+1]         data[i+1] = temp         swapped = true       end     end     return if !swapped   end end data = [10, 9, 8, 7, 6] bsort(data) puts "ソート結果#{data}" --------------------------------------------------- return if !swapped のところで、 なぜwhileのループから抜けられるのかがよくわかりません。 return if swapped == false と書き換えて実行しても同じ結果が得られたのですが、 数値の入れ替えがなければ swapped = false であるため、 !swappedはtrueとはならないのでしょうか。

  • Ruby
  • 回答数8
  • ありがとう数26

みんなの回答

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.8

そういうことでしたか。 whileの件は誤解が解けたようなので。 バブルソートは「隣同士の値を比べて、順位が逆なら入れかえる」を繰り返して、整列させるアルゴリズムです。 値に注目すると、それが泡が浮んでいくように徐々に移動するので「バブルソート」という名前が付いています。 入れ替えが発生すると、その前後の上下関係が変わってしまうことがあります。 ですから、もう一度全体を調べます。 入れ替えが発生しなかった、ということは、全ての箇所で順番通り、という意味です。 ということは、並び換えが完了している、ということです。 並び換えが終了したなら、処理を続ける必要はありません。 正月ですし、トランプが手許にあったら、次の指示通りにやってみましょう。 トランプの同じマークの一セットとジョーカーを用意します。 適当に混ぜたら、裏返しで横に並べます。(左から0,1,2,3..12とします) ※ ジョーカーを裏にします 0,1を表にします。  0の方が大きかったら2枚の位置を入れ替えます。ジョーカーを表にします。 0,1を裏返します。 1,2を表にします。  1の方が大きかったら2枚の位置を入れ替えます。ジョーカーを表にします。 1,2を裏返します。 ...(略) 11,12を裏返します。 ジョーカーが裏のままなら終了です。 そうでなければ、※から繰り返します。 全部表にしたら、どんな風に並んでいるでしょうか

jet888
質問者

お礼

再度回答いただきありがとうございます。 実際にトランプでバブルソートを試してみました。 全部表にしたらAからKまで左から順に並んでいました。 ジョーカーは裏になっています。 このトランプではジョーカーがswappedの役割を果たしているのですね。 実際にトランプで試してみると、バブルソートの仕組みが理解しやすく、 勉強になりました。 何度も回答いただきまして改めて感謝申し上げます。

  • siffon9
  • ベストアンサー率64% (136/211)
回答No.7

No.4です。 > return if !swapped の!swappedで、 > なぜ入れ替えを行わなかった場合、つまりswapped == falseの時のみ、 > returnでbsortを終了するのかについても教えていただけますでしょうか。 return if !swapped は以下の様に書き直せます。 if swapped == false  return end if文の動作はご存知だと思いますが、 swapped==falseの時にreturnが実行されます。 その場合には、メソッドbsortを終了します。 swappped==trueの場合はreturnが実行されません。 その場合は、while(true) ~ end のループを繰り返すことになります。 従ってwhileループが終了しないのでメソッドbsortを終了しません(下の※C点に到達しない) 以下に元のメソッドの簡略版を書いてみましたご理解の一助にしていただければ幸いです。 def bsort(data)   while true   # ループ条件が常に真なのでwhile~endを無限ループする           # (※A)     swapped = false     if 数値の入替があった場合      swapped = true # この場合は※Bでメソッドを終了しない     end     if swapped==false      return  # (※B) ここでメソッドを終了する(swappedがfalseの場合)     end   end       # 無限ループなので※Aに戻る           # (※C) swapped==trueの場合はここに到達しない end

jet888
質問者

お礼

再度回答いただきありがとうございます。 >return if !swapped は以下の様に書き直せます。 if swapped == false  return end このように記述していただけると理解できました。 また、メソッドの簡易版のプログラムも教えていただき、 大変わかりやすく勉強になりました。 別の回答者様の御礼コメントにも書かせていただきましたが、 >否定(NOT)は演算子「!」の右辺の条件式が真の場合に全体の式の評価が偽となり、右辺の条件式が偽の場合に全体の式の評価が真となります。 とサイトに書かれていたのですが、 全体の式の評価というのがよくわかっておらず、 return if !swapped の部分が理解できませんでしたが、 今回理解することができました。 何度も回答いただきまして改めて感謝申し上げます。

  • notnot
  • ベストアンサー率47% (4848/10262)
回答No.6

No1,3,5です。 >これは理解しておりましたが、while全体の値はreturnの後ろの値ではないのですね。失礼しました。 return は、whileと関係なく、メソッド定義からその値を持って抜け出します。 whileループの終了条件とか返す値とは次元の違う話です。 >return if !swapped の!はswappedの値を真から偽か、偽から真に変更するだけですよね? swappedの値は変更しませんよ。 return if !swappedは、 work = if swapped       false      else       true      end if work  return end みたいな感じです。workが偽の場合はその次の文の実行に移ります。 !swappedと書くとswappedの値が変化すると思っていたなら大きな間違いです。 どこでそんな考えを持ったのか、探った方が良いと思います。

jet888
質問者

お礼

再度回答いただきありがとうございます。 http://www.rubylife.jp/ini/if/index4.html このサイトを見ていたのですが、 >否定(NOT)は演算子「!」の右辺の条件式が真の場合に全体の式の評価が偽となり、右辺の条件式が偽の場合に全体の式の評価が真となります。 これを見て、!swappedと書くとswappedの値が変化する、 つまりswappedがfalseならtrueになると思っていたのですが、 (全体の式の評価というのがよくわかっていませんでした) そうではなくて、swappedがfalseならtrueを返すということなのですね。 >work = if swapped       false      else       true      end swappedがtrueならbsortにfalseを返し、 falseならtrueを返すということなのですね。 それで数値の入れ替えを行わなかった場合、 swappedがfalseであるためbsortにtrueを返してループを抜け、 入れ替えを行った場合はswappedがtrueとなるためbsortにfalseを返し、 ループさせるということなのですね。 大変わかりやすい回答をありがとうございました。 何度も回答いただきまして改めて感謝申し上げます。

jet888
質問者

補足

すみません、下の御礼コメントを訂正させていただきます。 >swappedがtrueならbsortにfalseを返し、 >falseならtrueを返すということなのですね。 >それで数値の入れ替えを行わなかった場合、 >swappedがfalseであるためbsortにtrueを返してループを抜け、 >入れ替えを行った場合はswappedがtrueとなるためbsortにfalseを返し、 >ループさせるということなのですね。 bsortにtrueあるいはfalseを返すのではなく、 workにtrueあるいはfalseを返し、 もしworkがtrueならreturnでメソッドから抜けるということですね。 失礼いたしました。

  • notnot
  • ベストアンサー率47% (4848/10262)
回答No.5

No1,3です。 >return のあとに何もないのでwhileにnilを返す、つまりtrueではないため やはりそういう誤解でしたか。No3に書いたとおりなのですが、 whileがループを継続するか終了するかは、while の直後に書かれた式の値を判断に使います。 endの直前の値は無関係です。 while true の場合は、whileループ自体としては、無限ループになります。 なお、while全体の値は、 ・ while 直後の値がfalse/nilでループを終了した場合は nil ・ break でループを終了した場合も nil ・ break 式 でループを終了した場合は 式の値 となります。いずれにせよ、end直前の値は無関係です。

jet888
質問者

補足

再度回答いただきありがとうございます。 >while true の場合は、whileループ自体としては、無限ループになります。 これは理解しておりましたが、while全体の値はreturnの後ろの値ではないのですね。失礼しました。 何度もお聞きして申し訳ないのですが、 return if !swapped の!はswappedの値を真から偽か、偽から真に変更するだけですよね? これだと値の入れ替えを行っても行わなくてもreturnでbsortを終了することにはならないのでしょうか?

  • siffon9
  • ベストアンサー率64% (136/211)
回答No.4

こんにちは > return のあとに何もないのでwhileにnilを返す、つまりtrueではないため > ループを抜けるのではないのでしょうか? returnの実行でif文を終了(= whileに戻る)のではありません。 whileのループを飛び越えて、メソッド bsort自体を終了します。 rubyリファレンスをご参照下さい。 http://docs.ruby-lang.org/ja/1.9.3/doc/spec=2fcontrol.html#return  > 式の値を戻り値としてメソッドの実行を終了します。

jet888
質問者

お礼

回答ありがとうございます。 >whileのループを飛び越えて、メソッド bsort自体を終了します。 returnはwhileに返すものだと勘違いをしておりました。失礼しました。 bsortにnilを返してメソッドの実行を終了するのですね。

jet888
質問者

補足

よろしければ、return if !swapped の!swappedで、 なぜ入れ替えを行わなかった場合、つまりswapped == falseの時のみ、 returnでbsortを終了するのかについても教えていただけますでしょうか。

  • notnot
  • ベストアンサー率47% (4848/10262)
回答No.3

No1です。 >入れ替えがない場合と同様にwhileにnilを返してループを抜けることにはならないのでしょうか? whileの条件はtrueなので、途中でreturnやbreakで抜けない限りはループし続けます。 「whileにnilを返す」というのが意味不明になってます。

jet888
質問者

補足

再度回答ありがとうございます。 return if !swappedは if !swapped   return end と同じ意味ですよね? return のあとに何もないのでwhileにnilを返す、つまりtrueではないため ループを抜けるのではないのでしょうか?

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.2

> 数値の入れ替えがなければ swapped = false であるため、 > !swappedはtrueとはならないのでしょうか。 考えが間違っています。 演算子 ! について、よく調べましょう。

jet888
質問者

お礼

回答ありがとうございます。 下のサイトを見ると、 http://www.rubylife.jp/ini/if/index4.html !aはaが真の時に偽、偽の時に真を返すとなっているので、 swapped = falseであれば、!swappedはtrueになると考えました。

  • notnot
  • ベストアンサー率47% (4848/10262)
回答No.1

>数値の入れ替えがなければ swapped = false であるため、 >!swappedはtrueとはならないのでしょうか。 それで合ってます。入れ替えが無ければ、swapped = false なので、!swapped==trueとなり、 ループを抜けます。!swappedの ! は、swappedがfalseかnilの時trueになり、それ以外の場合はfalseになる演算子です。 こう書き直した方が良いんじゃ無いかな。 def bsort(data)  swapped = true  while swapped   swapped = false   for i in 0..data.size-2    if data[i] > data[i+1]     data[i], data[i+1] = data[i+1], data[i]     swapped = true    end   end  end end

jet888
質問者

補足

回答ありがとうございます。 >!swappedの ! は、swappedがfalseかnilの時trueになり、それ以外の場合はfalseになる演算子です。 入れ替えがなければswapped==falseであり、 !swapped==trueとなり、whileにnilを返してループを抜けますよね? 入れ替えがあった場合ではswapped==trueであり、 !swapped==falseとなりますが、 入れ替えがない場合と同様にwhileにnilを返してループを抜けることにはならないのでしょうか? 教えていただいたプログラムのほうがわかりやすいですね。 >data[i], data[i+1] = data[i+1], data[i] これでdata[i] = data[i+1] と data[i+1] = data[i] を1行で表せるのですね。勉強になります。

関連するQ&A

  • rubyの構文(&&を用いた条件分岐について)

    ruby初心者です。 最近、ruby on railsで書かれたソースを引き継ぎ解析を行っています。 その中で、以下のような構文が出てきました。 ========================================= num = 0 bool = false vals = '' puts 'start' num == 0 && bool && if vals  puts 'true' else  puts 'false' end puts 'end' ========================================= 上記プログラムを実行すると、if ~ end までが実行されませんでした。 そこで、変数boolをtrueに変更して再実行したところ、if文が実行されました。 そこで私は、上記プログラムは以下と同値であると解釈しました。 ====================================== (省略) if num == 0 && bool  if vals   puts 'true'  else   puts 'false'  end end ======================================= 以上を踏まえて・・・ 1.私の解釈は正しいでしょうか? 2.間違っている場合、正しい処理の解釈を教えていただけますでしょうか?または参考URLを教えていただけますと助かります。 文の最後に"&&"がついている文を見たことがなく、ネットで調べても 正解らしいものが掲載されていなかったので質問させていただきました。 拙い説明で申し訳ありませんが、よろしくお願いいたします。

    • ベストアンサー
    • Ruby
  • 情報処理のバブルソートの問題について質問します。

    情報処理のバブルソートの問題について質問します。 #include <stdio.h> int main(void) { double x[5]={6.0, 9.0, 2.0, 10.0, 8.0}; int i,j; int n=5; double temp; /* 初期状態の表示 */ printf("並べ替え前の並びは以下の通り:\n"); for (i=0; i<n; i++) { printf("%f,\t",x[i]); } printf("\n"); for (i=0; i<n-1; i++) { for (j=i+1; j<n; j++) { if (x[j] > x[i]) { temp = x[i]; x[i]=x[j]; x[j]=temp; } } } printf("大きい順に並べ替えた結果は以下の通り:\n"); for (i=0; i<n; i++) { printf("%f,\t",x[i]); } printf("\n"); return 0; } というプログラムを用いて行ってみたのですが、 これは王様ソートというプログラムだと言われました。 どのように換えればバブルソートになるのでしょうか?

  • C++ ソートのやり方

    僕が作ったプログラムで、これはバブルソートなのかわからないので教えてください。 また、ほかのソートの仕方も教えてください。 よろしくお願いします。 汎用関数を使っているのでわかりにくいかもしれないですがお願いします。 #include <iostream> using namespace std; template <class X>void Sort(X *data, int size) { X temp; for (int i = 0; i < size; i++){ for (int j = i + 1; j < size; j++){ if (data[i]>data[j]){ temp = data[i]; data[i] = data[j]; data[j] = temp; } } } } int main() { int i[10]{1, 4, 3, 5, 2, 10, 2, 7, 6, 8}; char c[10]{'c', 'b', 'z', 'a', 'x', 'y', 'j', 'n', 'm', 'r'}; Sort(c, 10); Sort(i, 10); for (int j = 0; j < 10; j++){ cout << i[j] << ' '; } cout << endl; for (int j = 0; j < 10; j++){ cout << c[j] << ' '; } cout << endl; getchar(); return 0; }

  • Cでのバブルソートがよくわかりません

    C言語の課題でバブルソートのプログラミングをしています。入れるデータは10個で、降順に並び変えた最終的な結果だけでなく、毎回for文をまわす度にその時点での結果を表示させなければなりません。 そこで渡されたフローチャートを参考にしてプログラミングしてみたところ、以下のようになりました。しかしなかなか上手く行きません。C言語はまだまだ初心者なので、どなたかお力を貸していただけると助かります。 #include <stdio.h> main(){ int d[10] = {0,7,8,4,5,3,2,1,6,9}; int i,n,j,temp; for(i=1;i<j;i++){ for(j=1;j<=i;n--){ if(d[j]<d[j-1]){ temp=d[j]; d[j]=d[j-1]; d[j-1]=temp; } } for(i=0;i<=10;i++){ printf("%d ", d[i]); } } for(i=0;i<=10;i++){ printf("%d ", d[i]); } }

  • ソートプログラム

    ファイルから10個の整数が 29 45 11 2 86 91 33 62 77 59 のように一行に1個の形式で格納されている。このファイルから10個の整数を読み込み、選択法でソートし、この数字を小さい順に表示するプログラムを作成したのですが、ソート部分がうまくできません。どなたかどうすれば改善できるか教えてください。 <プログラム> #include<stdio.h> #include<stdlib.h> #define MAXN 100 int A[MAXN]; main() { _inputdata(); _selectionsort(1,10); _printdata(); } selectionsort(p,q) ___int p, q; { _int i, j, cmin, temp; _for(j = p; j <= q; j++){ __cmin = j; /* A[cmin]が現在の最小値 */ __for(i = j+1; i <= q; i++) ___if(A[cmin] > A[i]) cmin = i; __/* A[j]とA[cmin]との入れ換え操作 */ __swap(j, cmin); _} } swap(int x, int y) { _int temp; _temp = x; _x = y; _y = temp; } inputdata() { _FILE *fp; _if((fp=fopen("integers10.dat", "r"))==NULL) { __printf("ファイルが見つかりません: integers10.dat\n"); __exit(EXIT_FAILURE); _} _printf("データを入力\n"); _while(fscanf(fp, "%s", A)!=EOF) { ____printf("%s\n",A); _} _fclose(fp); } <コンパイル→実行> % gcc -o sort1 sort1.c % ./sort1 データを入力 29 45 11 2 86 91 33 62 77 59 ソート済みデータ 0 0 0 0 0 0 0 0 0 0 %

  • ソート

    読み込むファイル(sample.txt)は、 2,jirou 5,gorou 4,shirou 1,tarou 6,mutsuo 3,saburou 下記の処理をします。 #include<stdio.h> #include<string.h> #define N 6 int sort1[N]; char sort2[N][30]; int BubbleSort(int data[N]) { int i,j,flag; do{ flag=0; for(i=0;i<N-1;i++) { if(data[i]>data[i+1]) { flag=1; j=data[i]; data[i]=data[i+1]; data[i+1]=j; } } } while(flag==1); return 0; } int main(void) { FILE *fpin; int id,h,k; printf("\n"); fpin=fopen("sample.txt","r"); if(fpin==NULL){ printf("ファイルをオープンできず!\n"); return 1; } for(k=0;k<N;k++) { h=fscanf(fpin,"%d,%s",&sort1[k],sort2[k]); if(h==EOF) break; printf("%d %s\n",sort1[k],sort2[k]); } printf("\n"); BubbleSort(sort1); for(k=0;k<N;k++) printf("%d %s\n",sort1[k],sort2[k]); return 0; } 実行結果は、 2 jirou 5 gorou 4 shirou 1 tarou 6 mutsuo 3 saburou 1 jirou 2 gorou 3 shirou 4 tarou 5 mutsuo 6 saburou 名前(sort2)もソートさせるには、どうすればいいか手ほどきをお願いします…

  • ソートプログラムについて

    ソートプログラムとして以下のように作成しました。 int main( ) { int i, j, temp; int ten[10] = { 98,34,67,89,99,23,54,21,10,65 }; for (i=0; i< 9; i++) { for(j=i+1; j<10; j++) { if (ten[i] < ten[j]) { temp = ten[i]; ten[i] = ten[j]; ten[j] = temp; } } } for (i = 0; i < 10; i++) { printf("SORT[%d] = %d\n",i,ten[i]); } } このプログラムを昇順で同じ数字が入力された場合、出力表示として 例: SORT[1]=99 SORT[2]=98 SORT[2]=98 SORT[3]=89 SORT[4]=70 というようにしたいのですが、プログラムをどのように 書いていけば良いのかわかりません。 例のような出力にするにはどのようにすればいいのでしょうか 教えて下さい。

  • クイックソート(C言語)

    こんにちは<_ _> クイックソートについての質問です。 左端を軸にクイックソートでデータを昇順にソートする プログラムを作ったのですがうまく動きません #include<stdio.h> void quick(int *,int,int); #define N 10 int main(void) { static int a[]={41,24,76,11,45,64,21,69,19,36}; int k,b=0; quick(a,0,N-1); for(k=0;k<N;k++) printf(" %d",a[k]); return 0; } void quick(int a[],int left,int right) { int s,t,i,j; t=right; i=left+1; j=a[left]; if(right>left){ while(1){ while(a[++i]>j); while(a[--t]<j && t>0); if(i>=t){ break; } s=a[i]; a[i]=a[t]; a[t]=s; } s=a[i]; a[i]=j; a[left]=s; quick(a,left,t-1); quick(a,t+1,right); } } 値の入れ替え、軸の入れ替えもしましたが結果として 「41 41 76 69 45 64 41 19 0 36」 このような結果で出力されてしまいます・・・ 時間に余裕のある方いましたらご指導をお願いします。 よろしくお願いします。<_ _>

  • 計算の途中経過を表示

    以下のようなプログラムで、素数をカウントダウンする事が出来るのですが、このくらいのサイズだとどうしても次の素数が表示されるまで時間がかかります。 そこで以下のものを修正して、今どの数に取りかかっていて、どの約数(i)で割っているのか常に画面に表示されるようにしたいのです。値が画面で目まぐるしく変わってもかまいません。是非助けてください。 def prime(val) maxv = Math::sqrt(val).truncate (2..maxv).each do |i| return false if val % i == 0 end return true end x = 10**17+1 until x<10**16 until prime(x) x=x-2 end puts x x=x-2 end puts x

    • ベストアンサー
    • Ruby
  • 【ruby】【文法?】ブロックをbreakした時。。

    質問を見ていただいて有難うございます。 質問を一言で言うと、 「メソッドの中で呼び出し元がbreakを使った事を検知できるか?」 となるのでしょうか。。。以下に詳しく質問を記述いたします。 引数に配列を渡すと、その配列をブロックに一つずつ返してくれる メソッドhoge()があるとします。 以下の様に使います。 ------------------------------------- hoge([0,1,2]) do |x|  puts x end 実行結果 0 1 2 ------------------------------------- このhoge()は、実行中にエラーが発生した場合、トラップして falseを返す事とします。(何事もなければtrueを返します。) このhoge()を以下の様に書きました。 def hoge(arg)  begin   arg.each do |x|    yield x   end  rescue   false  else   true  end end 以下の様に使います。 ------------------------------------- ret=hoge([0,1,2]) do |x|  puts x end puts ret ? 'success' : 'fail' 実行結果 0 1 2 success ------------------------------------- ------------------------------------- ret=hoge(nil) do |x|  puts x end puts ret ? 'success' : 'fail' 実行結果 fail ------------------------------------- ここまでは、よかったのですが、hoge()のブロックの中で、breakを使うと hoge()の戻り値はnilになってしまいます。 ------------------------------------- ret=hoge([0,1,2]) do |x|  break if x==1  puts x end puts ret puts ret ? 'success' : 'fail' 実行結果 0 nil fail ------------------------------------- ここで質問です。 最後の例は、hoge()として異常系ではないので、retにtrueを与えたいのですが、どうしたらよいでしょうか? ご指導のほど、宜しくお願いいたします。

    • ベストアンサー
    • Ruby

専門家に質問してみよう