• ベストアンサー

バブルソートの実行時間について

バブルソートで降順、ランダム順に並んでいるデータを読み込ませて昇順に並び替える実行時間について質問です。 バブルソートにおける計算時間は、データ数が多いほど、並び替える回数が多いほど長くなるはずですが、実際に実行したところ、並び替える回数が多いはずの降順のほうがランダム順よりも早くなりました。 なぜこのようになるのですか? よろしくお願いします。

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

  • ベストアンサー
  • S117
  • ベストアンサー率40% (18/45)
回答No.6

CPUの分岐予測が原因ではないでしょうか。 ※分岐予測についてはWikipediaを参照してください。 逆順のデータに対しては、常に入れ替え動作をします。 分岐予測の種類によりますが、常に「実行されるとCPUが予測している」なら、パイプラインを最大限に活用して高速な処理を実現できます。 一方、ランダムなデータであれば、分岐結果が一定ではないので予測の失敗が多発します。この場合パイプラインを生かし切れずに性能が劣化します。 今回の場合入れ替え動作自体がごく単純であるがために、予測に失敗することによるオーバーヘッドのほうが大きくなっているのでしょう。 期待する結果を得るには、入れ替え動作自体のオーバーヘッドが大きくなるようにする必要があります。たとえば大きな構造体を使うようにします。 ただし、普通大きな構造体などを利用する場合、ポインタを使います。ポインタであれば入れ替えのオーバーヘッドが小さくなります。 結局、 「適切な分岐予測をするCPUでのバブルソートでは、逆の順序に並べたデータの処理は、ランダムに並んだデータよりも早い」 という結論になります。

参考URL:
http://ja.wikipedia.org/wiki/%E5%88%86%E5%B2%90%E4%BA%88%E6%B8%AC
sirokko045
質問者

お礼

回答ありがとうございます。 s117さんの回答と補足資料を見る限り、これが原因であるとみて間違いないようですね。 CPUにはそのような機能もあるんですね、勉強になりました。 ご回答いただきありがとうございました。

その他の回答 (5)

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

>このif文を何回実行しているかを数える方が、 これは正確な回答ではありませんでした。 「このif文を実行した結果が何回真になったか」が正しいです。 つまり、降順にきれいに並んでいるデータと ランダムに並んでいるデータとで、 実際の入れ替え処理を何回実行したか、を比べてみては?ということです。

sirokko045
質問者

お礼

すいません、こちらに書くべきでしたね。 何度もご回答いただき、ありがとうございました。

sirokko045
質問者

補足

回答ありがとうございます。 if文の下にカウンターをつけて実行したところ、 ランダム順 約25億 降順    約 7億 という結果になりました。 これはコンパイラの処理の仕方によって異なるのかなと考えましたが、s117さんの回答と資料を拝見したところ、CPUの分岐予測が原因ではないかという結論にたどり着きました。 何度もご回答いただき、ありがとうございました。

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

ソート後のデータを出力するよりも、 >if(str[j-1]>str[j]){ このif文を何回実行しているかを数える方が、 問題解決にとって有益かもしれません。

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

>バブルソートの部分のソースを提示させていただきます。 提示された箇所以外はこちらで勝手に書いてもいいのですか? 当方で、あなたのところとできるだけ同じ条件で実験するためには、 お手持ちのコードを「そっくりそのまま」載せてくださる方がよいと思います。 いかがでしょうか。

sirokko045
質問者

補足

申し訳ございません。ソースコード全体を提示させていただきます。 #include<stdio.h> #include<stdlib.h> #include<time.h> int main(int argc,char **argv){ int i,j,temp; int count=0; int str[1000000]; clock_t c_start,c_end; FILE *fp; if(argc!=2){ fprintf(stderr,"File has not been opened\n"); exit(1); } if((fp=fopen(argv[1],"r"))==NULL){//ファイルを読み込む fprintf(stderr,"File has not been opened\n"); exit(1); } while(fscanf(fp,"%d",&str[count]) != EOF) {//EOFまで1行づつデータを読み込む count++; } c_start=clock();//クロックスタート for(i=0;i<count;i++){//バブルソートを行う for(j=count;j>i;j--){ if(str[j-1]>str[j]){ temp=str[j]; str[j]=str[j-1]; str[j-1]=temp; }//End if }//End for j }//End for i c_end=clock();//クロックストップ printf("permute it in ascending order\n"); for(i=0;i<count;i++) printf("%d\n",str[i]);//ソート後のデータを出力する printf("Time:%f\n",(double)(c_end-c_start)/CLOCKS_PER_SEC);//実行時間の出力 return 0; }//End main よろしくお願いします。

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

どういったソースコードで実験されたかを提示してください。

sirokko045
質問者

補足

回答ありがとうございます。 バブルソートの部分のソースを提示させていただきます。 c_start=clock();//クロックスタート for(i=0;i<count;i++){//count=データ数 for(j=count;j>i;j--){ if(str[j-1]>str[j]){ temp=str[j]; str[j]=str[j-1]; str[j-1]=temp; }//End if }//End for j }//End for i c_end=clock();//クロックストップ なお、他のソースコードで実験した人も同様の結果になったので、ソースコードが原因ではないと考えています。

  • BLK314
  • ベストアンサー率55% (84/152)
回答No.1

>なぜこのようになるのですか? 測定方法(データ数はいくつなのか?、 1回の測定か0、何回かの平均値か?等)、 及び測定環境(CPU, メモリ、OS等)が明示されていないので、 原因は分かりません。 可能性をあげることはできます。 例えば、降順、ランダム、1回きりの場合で Windows上でシングルCPU(HTもない)で測定した場合に、 たまたま、ランダム測定中に別プロセスにタスク・スイッチが切り替わった。 GetTickCount()での時間測定なので、 他のタスク実行時間も含めて評価してしまった。 とか、 データ数がCPUのキャッシュに全部収まる範囲だったので 後に実行した場合は、キャッシュアクセスで済んでしまった。 等々 何回かの平均をとらないと、比較に耐えるデータにはならないと おもいますが、平均をとったかいなか文章からは読み取れません。 条件を明示してください。

sirokko045
質問者

補足

回答ありがとうございます。条件が不足していてすいません。 データ数は100000個でそれぞれ3回ずつ実行しました。これは学校の実験で行ったのですが、他の人も同じ結果になっていました。(バブルソートのソースはみんなバラバラです) OSはLINUXです。メモリ、CPUはわかりません。 使用したコンパイラはgccで、emacsを使用しました。 よろしくお願いします。

関連するQ&A

  • バブルソートで並べ替え

     学校でC言語入門をやっています。今回「バブルソート」で配列の要素を降順(大きい順)に並べ替えるということをやっています。  バブルソートの原理はわかりましたが、書き方がよくわかりません。まず簡単な配列として、a[5]={5,2,24,8,31} というものを考えています。    for(k=0;k<n-1;k++){ if(a[k]<a[k+1]){ t=a[k];a[k]=a[k+1];a[k+1]=t; } } とすると、全範囲の中でバブルソートをおこなうので一番小さい"2"が a[4] に入り、位置の確定ができます。  今度は確定していない範囲でバブルソートをおこなうと for(m=0;m<k;m++){ if(a[m]<a[m+1]){ t=a[m];a[m]=a[m+1];a[m+1]=t; } } と先ほどと同様に書け、この中で一番小さい"5"が a[3] に確定します。以下同様に、範囲をせばめていきあと2つ for文を書くと全ての要素の位置が確定することになりますが、これは要素の数が多くなるととても大変なので複数の for文を1つのfor文でまとめたいのですがよくわかりません。  あと、バブルソートには上と下から(左と右から)の両方から査定する「カクテルシェイカソート」というものもあるらしいのですが、今回は一方向からの査定でやるという指示なのでよろしくお願いします。

  • バブルソート

    int a[] = {8,45,15,90,62,73,22}をバブルソートを使用して、降順で並べ替える。 以下の説明では、配列の要素数(ここでは7)をNとしている。 (1) a[N-1] と a[N-2] を比較し、a[N-1] が a[N-2] より大きい場合は、a[N-1] と a[N-2] を入れ替える。   同様に a[ j] が a[ j-1] より大きければ、a[ j] と a[ j-1] を入れ替える。   この操作を、j=N-1からiまで繰り返す。ただし、iは(1)の処理回数を表す値である。(初回を0とする) (2) (1)を i=0 から N-2 まで繰り返す。 (3) 以下の<実行例>を参考に、配列aのようその各値を標準出力する。 <実行例> 90 73 62 45 22 15 8 という問題なのですが、どうやってもうまく並び替えられません。 a[N-1] の処理はいらないのではないのですか? どのようにプログラムを書いたらいいのか教えて下さい。 あつかましいですが、できたら解説付きでお願いします。

    • ベストアンサー
    • Java
  • バブル・ソート、クイック・ソート

    N個(N=4,5,6)のデータが全て等しいデータ列(例えばN個の数字全部が1のとき)をバブルソートで並び替えたとき、データの交換回数は何回か。また、同じデータ列をクイックソートで並び替えたときはどうか。 という問題があるのですが、どう比較するのかがわかりません。詳しい方、説明よろしくお願いします。

  • modified bubble sort

     ソーティングについて教えてください.  ソーティングの手法に,バブルソートというものがあります(隣接するふたつを入れ替える).このソーティングでは,最大交換回数は要素数が n のとき, n(n-1)/2 となります.  隣接する要素の交換に加え,先頭と最後の要素の入れ替えも可能だとすると(イメージとしては,サイクリックなバブルソートです),最大交換回数は n^2/4 となるそうです.  この n^2/4 になる,という理由が分かりません(普通のバブルソートが n(n-1)/2 になるのは理解できます).どなたかご教授頂ければと思います.

  • バブルソートを入れたいのですが

    こんにちは、Perlを始めたばかりの初心者です。 さっそく質問の方失礼します。 乱数1~100までの数字のうち20個をとりだし配列にいれ、数字を昇順に入れ替えして昇順前と昇順後の数字を表示する問題なのですが。 @a[100]=(1..100); srand(time()); for($i=0 ; $i<20 ; $i++){ $a=int(rand(@a)); print"$a\n"; } と上記の乱数20個を取り出すことができたのですが、 そのあとの昇順させようとしてバブルソートを利用したいのですが、どのように組み込めばいいかわかりません。 どのように組み込めばいいのでしょうか? お答えの方ヨロシクお願いします。

    • ベストアンサー
    • Perl
  • C#でバブルソート

    テキストボックスに任意の整数を複数個入力し、ボタンを押すことで入力した数字を別のテキストボックスに昇順・降順表示するプログラムを作りたいと思っています。 例えば 入力用テキストボックスに1、10、5をキーボードで入力 ↓ 作っておいた「昇順に並び替え」のボタンをクリック ↓ 出力用テキストボックスに1、5、10と表示される (「降順に並び替え」のボタンをクリックした場合は、10、5、1と表示) といった感じです。 バブルソートを使って作りたいのですが、超初心者のため、数字同士の比較?や、テキストボックスへの出力の仕方が全く分かりません。 分かりにくい文章のみの状況説明になってしまいましたが、ご指導よろしくお願いします。 マイクロソフトのビジュアルのC#プロジェクトです。

  • csvファイル内にてソートする方法

    ご協力お願いします。 あるログデータを取得したcsvファイルを作成しました。しかし、データ量も多く見やすいようにソートをかけたいのですが方法がわかりません。csvファイルの中身は以下のようになっています。 ___________________________ | 端末ID | ユーザーID | 日付 | 時間 | ――――――――――――――――――――――――― | ITD002 | 00000001 |2005/08/22| 11:00 | ――――――――――――――――――――――――― | ITD002 | 00000003 |2005/08/22| 21:00 | ――――――――――――――――――――――――― | ITD001 | 00000001 |2005/08/22| 12:00 | ――――――――――――――――――――――――― | ITD001 | 00000002 |2005/08/22| 18:20 | ――――――――――――――――――――――――― 以上のような中身になっています。レコード量は、もっと多いです。このランダムな順番に取得したレコードを 端末ID(昇順)ユーザーID(昇順)日付(降順)時間(降順)でソートする方法をご教授お願いします。

  • ソートに関する質問です

    C言語でのプログラム作成の課題が解けなくて困っています。 バブルソートを使って、1000000個の整数データを昇順に並べ替えるプログラムを作成するというものです。 自分なりに作成したプログラムは、mallocでデータを格納する動的領域を確保して、後はシンプルにバブルソートの処理を行っています。 データ数が5,6万程度なら正常な動作が確認できるのですが、それより大量のデータ数だと、処理に時間が掛かりすぎるせいか、もしくは処理しきれずに動かなくなってしまったのか分かりませんが、プログラムの処理がいつまでたっても終わりません。 おそらくバブルソートの2重ループのあたりで、膨大な処理になってしまうのだと思うのですが、この問題についての改善策をどなたかご教授いただけませんでしょうか。

  • ソートアルゴリズム

    お忙しいところすいません。 先日授業で出された課題がどうしても分からなかったので教えていただきたいと思っています。 どうやってプログラムを作ればよいでしょうか。 問題は、 『N件の乱数データを用意し、昇順(または降順)に並べる。 データ件数、ソート所用時間を表示する。 ソート時間1~100秒で処理できるデータ件数を確認する。 ソートアルゴリズムは2種以上作成すること。』 です。

  • sortコマンドの使い方

    一列目はクラス、二列目はテストの点数、三列目は氏名からなるデータ: # data.txt ---------- 1 80 安倍 1 100 小泉 1 90 小沢 2 80 松坂 2 70 松井 2 100 鈴木 ------------- があります。 これを sortコマンドで (1) 1列目昇順 (2) 2列目降順 で並び替えて # data2.txt ---------- 1 100 小泉 1 90 小沢 1 80 安倍 2 100 鈴木 2 80 松坂 2 70 松井 ------------- のように、クラスごとに得点順に並び替えたいと思っています。 sort のオプションは -k が並び替えの基準の列の指定 -r が逆順 -g が数値データ なので cat data | sort -grk2 | sort -k1 としてみましたがうまく行きません。 一つめ「sort -r -k2」でせっかく二列目降順に並び替えているのに、二つめ(右)の sort -k1 でその結果が無くなってしまって 1 100 小泉 1 80 安倍 ← !! 1 90 小沢 ← !! 2 100 鈴木 2 70 松井 ← !! 2 80 松坂 ← !! のようになってしまいます。 どうすればよいでしょうか?

専門家に質問してみよう