第21講 並び替えの方法その1 
第4話 隣項交換繰り返し法解説その2
今日は、
void f(int a,int *m){
  int i;
  i=0;
  while(i<a){
    m[i]=rand()%100;
    if(m[i]<10)cout<<" "<<m[i]<<" ";
    if(m[i]>=10)cout<<m[i]<<" ";
    if(i>0 && (i+1)%25==0)cout<<endl;
    i++;
  }
  cout<<endl;
}
void g(int a,int *m){
  char t=1;
  int i,v,w,cn;
  cn=0;
  while(t){
    v=0;
    for(i=0;i<a-1;i++){
      if(m[i]<m[i+1]){
        w=m[i];
        m[i]=m[i+1];
        m[i+1]=w;
        v++;
      }
    }
    if(v==0)t=0;
    cn++;
  }
  cout<<"並び替え後"<<endl;
  i=0;
  while(i<a){
    if(m[i]<10)cout<<" "<<m[i]<<" ";
    if(m[i]>=10)cout<<m[i]<<" ";
    if(i>0 && (i+1)%25==0)cout<<endl;
    i++;
  }
  cout<<endl<<cn<<"巡目で並び替えに成功しました。"<<endl;
}
の部分を解説しましょう。
void f(int a,int *m){
  int i;
  i=0;
  while(i<a){
    m[i]=rand()%100;
    if(m[i]<10)cout<<" "<<m[i]<<" ";
    if(m[i]>=10)cout<<m[i]<<" ";
    if(i>0 && (i+1)%25==0)cout<<endl;
    i++;
  }
  cout<<endl;
}
については解説は必要ありませんね。
100未満の整数をランダムに発生させ、
それを配列(実際にはポインタ)に収納しています。
rand()は、10万以内ぐらい(曖昧な言い方で済みません。正確にはわかりません。)
の0以上の整数をランダムに発生させます。
a%bはaをbで割った余りを求める式ですから、
rand()%100で100未満の整数になります。
100にしたとは特に理由はありません。
1000でも10000でも好きに設定してください。
このループはもちろんfor文で行ってもよいわけですが、
while文を学習したばかりですので、
復習のためwhile文にしてみました。

void g(int a,int *m){
  char t=1;
  int i,v,w,cn;
  cn=0;
  while(t){
    v=0;
    for(i=0;i<a-1;i++){
      if(m[i]<m[i+1]){
        w=m[i];
        m[i]=m[i+1];
        m[i+1]=w;
        v++;
      }
    }
    if(v==0)t=0;
    cn++;
  }
  cout<<"並び替え後"<<endl;
  i=0;
  while(i<a){
    if(m[i]<10)cout<<" "<<m[i]<<" ";
    if(m[i]>=10)cout<<m[i]<<" ";
    if(i>0 && (i+1)%25==0)cout<<endl;
    i++;
  }
  cout<<endl<<cn<<"巡目で並び替えに成功しました。"<<endl;
}
が今回の目玉、核となる部分です。
並び替えプログラムです。
 while(t){
    v=0;
    for(i=0;i<a-1;i++){
      if(m[i]<m[i+1]){
        w=m[i];
        m[i]=m[i+1];
        m[i+1]=w;
        v++;
      }
    }
    if(v==0)t=0;
    cn++;
  }
はfor文でもできますが、
while文の方が向いていると言えます。
何故かと申しますと、
今回はプログラマーは、何回で終了するかは把握できません。
下限や終了回数がわかっているときは、
for文の方がわかりやすいわけですが、
下限・終了回数がわからないときは、
while文が向いていると言えます。

この隣項交換繰り返し法の終了はどういうときでしょうか。
4,9,3,8,10
の場合
4,9,3,8,10
9,4,3,8,10
9,4,3,8,10
9,4,3,8,10
9,4,8,3,10
9,4,8,3,10
9,4,8,10,3
1巡目が終わりです。
9,4,8,10,3
9,4,8,10,3
9,8,4,10,3
9,8,4,10,3
9,8,10,4,3
9,8,10,4,3
2巡目が終了しましたが、まだ降順になっていません。
3巡目に入ります。
9,8,10,4,3
9,8,10,4,3
9,10,8,4,3
9,10,8,4,3
9,10,8,4,3
3巡目終了時にもまだ、降順になっていません。
9,10,8,4,3
10,9,8,4,3
10,9,8,4,3
10,9,8,4,3
10,9,8,4,3
すべての隣項を比較したとき、
左の項が右の項より小さくないとき、
終了です。
つまり、隣項の交換が1回も行われないときに終了です。
vは交換回数を数えています。
 while(t){
    v=0;
    for(i=0;i<a-1;i++){
      if(m[i]<m[i+1]){
        w=m[i];
        m[i]=m[i+1];
        m[i+1]=w;
        v++;
      }
    }
    if(v==0)t=0;
    cn++;
  }
新しいループに入るときvを0にセットしています。
1回でも交換が行われた場合、まだ降順になっていない可能性がありますので、
その場合にはループ処理を繰り返さないとなりません。
しかし、交換回数0なら降順すなわち大きい順に並んでいることになります。



さて、課題を出して今話を閉じましょう。
今回
  while(t){
    v=0;
    for(i=0;i<a-1;i++){
      if(m[i]<m[i+1]){
        w=m[i];
        m[i]=m[i+1];
        m[i+1]=w;
        v++;
      }
    }
    if(v==0)t=0;
    cn++;
  }
をループ文で処理しましたが、
関数の再帰的呼び出しでもできます。
考えてみましょう。


第3話へ 第5話へ

戻る

C言語 C++講義第1部へ
C言語 C++講義第2部へ
VB講義へ
VB講義基礎へ

vc++講義へ第1部へ
初心者のための世界で一番わかりやすいVisual C++入門基礎講座
初心者のための世界で一番わかりやすいVisual Basic入門基礎講座
初心者のための世界で一番わかりやすいVBA入門講義(基礎から応用まで)