第12講 様々な並び替えの方法
第6話 並び替え第3の方法

前話で、隣同士を比較して大きい順に並び替えていってそれをN(Nはデータ数)回繰り返したことによる、
並び替えを考えました。
しかし、この方法だとNの2乗回ループを繰り返さなければなりません。

例えば、データ数が100個なら10000回、データ数が100000個なら10000000000回もループを繰り返さなければなりません。
これだとさすがのコンピュータも処理に時間がかかってしまいます。
そこで、第5話の方法の改良を考えたいと思います。
最初にデータを大まかに5分類してから並び替えをするようにさせたいと思います。
まず、最大値と最小値を求めます。
次に、最大値と最小値の差を求めそれを4で割ったものを幅としてそれで分類するのです。

データ数が10個で
41 67 34 0 69 24 78 58 62 64
である場合を例に説明すると、
最大値が78、最小値が0ですから、
(最大値−最小値)÷4=19.5です。
これを使って次のように分類します。
第1群 78以下で58.5より大きい場合 該当は67,69,78,62,64
第2群 58.5以下で39より大きい場合 該当は41,58
第3群 39以下で19.5より大きい場合 該当は34,24
第4群 19.5以下で0以上の場合  該当は0

最初の分類でデータは
67 69 78 62 64 41 58 34 24 0
となります。
これで前回の並び替え
       void Nb(int* p,int n){
           char i,j;
           int w,cn;
           for(i=0;i<n-1;i++){
             cn=0;
             for(j=0;j<n-1;j++){
               if(p[j]<p[j+1]){
                 w=p[j];
                 p[j]=p[j+1];
                 p[j+1]=w;
                 cn++;
               }
             }
             if(cn==0)break;
           }
           String^ v=L"";
           for(i=0;i<n;i++) v+=(p[i]).ToString()+L" ";
             textBox8->Text=v;
       }
を適用すると、3回のループで終わります。
分類を行わず41 67 34 0 69 24 78 58 62 64 のままで並び替えに掛けると、10回のループになります。
明らかに4分類してから、並び替えをした方が効率がいいことが分かります。
さらに、データ数が大きい場合の実験結果も示しておきましょう
41 67 34 0 69 24 78 58 62 64 5 45 81 27 61 91 95 42 27 36 91 4 2 53 92 82 21 16 18 95 の場合は、
分類しないで並び替えると29ループであるのにたいして7ループです。計算回数は30×29=870回に対して、
分類する場合は分類に要した計算回数も含めて計算して30×(7+4)=330回で、計算回数は約37%で済んでいます。
また、47 26 71 38 69 12 67 99 35 94 3 11 22 33 73 64 41 11 53 68 47 44 62 57 37 59 23 41 29 78 の場合は、
ループ数は28VS5となり、計算回数は840回VS270回で、約3分の1です。
データ数が多いほど、分類した方が有利になります。
例えば、データ数100の
33 15 39 58 4 30 77 6 73 86 21 45 24 72 70 29 77 73 97 12 86 90 61 36 55 67 55 74 31 52 50 50 41 24 66 30 7 91 7 37 57 87 53 83 45 9 9 58 21 88 22 46 6 30 13 68 0 91 62 55 10 59 24 37 48 83 95 41 2 50 91 36 74 20 96 21 48 99 68 84 81 34 53 99 18 38 0 88 27 67 28 93 48 83 7 21 10 17 13 14
の場合、ループ数は87VS22で、計算回数は8700回VS2600回となり、約3.3分の1となります。節約回数は、6100回にも及びます。

プログラム例を示して第6話は閉めたいと思います。
まず、フォームは次のようになっています。

そして、コードは下記の通りです。
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
         int a[N];
         int n=int::Parse(textBox1->Text);
         ds(a,n);
         if(n>9)Br(a,n);
         Nb(a,n);
      }
      void Br(int* p,int n){
         char i,j;
         int w=0;
         int max=0,min=100;
         for(i=0;i<n;i++){
           if(max<p[i])max=p[i];
           if(min>p[i])min=p[i];
         }
         textBox3->Text=max.ToString();
         textBox4->Text=min.ToString();
         double hb;
         hb=((double)max-(double)min)/(double)4;
         char a[4][N];
         char cn[4];

         for(i=0;i<4;i++){
           cn[i]=0;
           for(j=0;j<n;j++){
             if(i<3){
               if(p[j]>max-(i+1)*hb && p[j]<=max-i*hb){
                 a[i][cn[i]]=p[j];
                 cn[i]++;
               }
            if(i==3){
               if(p[j]>=max-(i+1)*hb && p[j]<=max-i*hb){
                 a[i][cn[i]]=p[j];
                 cn[i]++;
               }
             }
           }
        }
        char ks=0;
         for(i=0;i<M+1;i++){
           if(cn[i]>0){
             for(j=0;j<cn[i];j++){
               p[ks]=a[i][j];
               ks++;
             }
           }
        } 
    }
    void Nb(int* p,int n){
       char i,j;
       int w,cn;
       for(i=0;i<n-1;i++){
         cn=0;
         for(j=0;j<n-1;j++){
           if(p[j]<p[j+1]){
             w=p[j];
             p[j]=p[j+1];
             p[j+1]=w;
             cn++;
           }
         }
         if(cn==0){
            textBox6->Text=(i+1).ToString();
            break;
         }
       }
       String^ v=L"";
       for(i=0;i<n;i++) v+=(p[i]).ToString()+L" ";
       textBox5->Text=v;
    }
    void ds(int* p,int n){
       int i;
       String^ w=L"";
       for(i=0;i<n;i++){
         p[i]=rand() % 100;
         w+=(p[i]).ToString()+L" ";
       }
       textBox2->Text=w;
    }

(コピーペースト用
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
int a[N];
int n=int::Parse(textBox1->Text);
ds(a,n);
if(n>9)Br(a,n);
Nb(a,n);
}
void Br(int* p,int n){
char i,j;
int w=0;
int max=0,min=100;
for(i=0;i<n;i++){
if(max<p[i])max=p[i];
if(min>p[i])min=p[i];
}
textBox3->Text=max.ToString();
textBox4->Text=min.ToString();
double hb;
hb=((double)max-(double)min)/(double)4;
char a[4][N];
char cn[4];

for(i=0;i<4;i++){
cn[i]=0;
if(i<3){
for(j=0;j<n;j++){
if(p[j]>max-(i+1)*hb && p[j]<=max-i*hb){
a[i][cn[i]]=p[j];
cn[i]++;
}
}
}
if(i==3){
for(j=0;j<n;j++){
if(p[j]>=max-(i+1)*hb && p[j]<=max-i*hb){
a[i][cn[i]]=p[j];
cn[i]++;
}
}
}
}
char ks=0;
if(cn[i]>0){
for(i=0;i<4;i++){
for(j=0;j<cn[i];j++){
p[ks]=a[i][j];
ks++;
}
}
}
}
void Nb(int* p,int n){
char i,j;
int w,cn;
for(i=0;i<n-1;i++){
cn=0;
for(j=0;j<n-1;j++){
if(p[j]<p[j+1]){
w=p[j];
p[j]=p[j+1];
p[j+1]=w;
cn++;
}
}
if(cn==0){
textBox6->Text=(i+1).ToString();
break;
}
}
String^ v=L"";
for(i=0;i<n;i++) v+=(p[i]).ToString()+L" ";
textBox5->Text=v;
}
void ds(int* p,int n){
int i;
String^ w=L"";
for(i=0;i<n;i++){
p[i]=rand() % 100;
w+=(p[i]).ToString()+L" ";
}
textBox2->Text=w;
}



かなり難解なプログラムとなっていますので、次回以降詳しく解説いたします。


第11講第6話へ 第12講第5話へ 第12講第7話へ 第13講第1話へ




vc++講義第1部へ
vb講義へ
VB講義基礎へ
初心者のための世界で一番わかりやすいVisual Basic入門基礎講座へ
初心者のための世界で一番わかりやすいVisual C++入門基礎講座へ