第12講 様々な並び替えの方法
第8話 分類法ソースコードの解説
さて、お約束の通り第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;
    }
の解説を行いましょう。
まず、int a[N];で配列を宣言しています。Nは冒頭で、 const int N=30;(第12講第5話)と宣言されていますので、
30です。つまり、要素数(0を含めた添え字数)30の整数型の1次元配列aを宣言したことになります。
2行目のint n=int::Parse(textBox1->Text);では、

textBox1より、値を取得しています。
int::Parse(*)は*を整数型に変換する命令でした。
textBox1->Textに入っているのは、見かけは数字でも実際には文字でしたよね。
例えば、textBox1に100と入力されている場合、これは数字の100ではなく、文字の100です。
理由は、textBoxには文字しか入れられないからです。
だから、文字型を強制的に整数型に変換しなければならないのです。
強制的に変換しているのが、int::Parse(textBox1->Text)というわけです。
ds(a,n);はデータ作成関数void ds(int* p,int n)へ飛びなさいという命令です。
その際の引数が、配列aの最初のアドレスと先のn=int::Parse(textBox1->Text);によって取得したデータ数nです。
データ作成関数void ds(int* p,int n)では、データの作成が行われます。
       for(i=0;i<n;i++){
         p[i]=rand() % 100;
         w+=(p[i]).ToString()+L" ";
       }
によって、nこのデータが作成されます。rand() % 100は100以下の正の整数をランダムに発生させます。
1000以下の正の整数をランダムに発生させたいなら、rand() % 1000と変更すればよいのです。
なぜ、rand() % 100で100以下の正の整数が発生するかというと、rand() は10万以下の整数をランダムに発せさせる関数であり、
その関数で発生した整数を% 100で100で割った余りに換算しているからです。
textBox2->Text=w;で
のデータの右のtextBox2に値を入力しています。
次の、if(n>9)Br(a,n);ではデータ数が10以上ならデータ分類関数void Br(int* p,int n)を呼び出しなさいと命令しています。
データ数が少ない場合、分類してもメリットがないからです。
データ分類関数void Br(int* p,int n)が今回のメインです。
ここでは、データの最大値と最小値の差を求め、その差を4等分した幅で、データを4つの群に分けています。
        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;     
においては、分類幅を計算させています。(double)は整数型を強制的に実数型に変換させています。
実数型に変換しないと、小数点以下が丸められ整数になってしまうからです。
そして、いよいよメインの中のメイン
         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]++;
               }
             }
           }
        }
に到りました。ここで、4群への分類が行われています。
cn[0]、cn[1]、cn[2]、cn[3]は4群のデータ数をカウントするための変数です。
           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]++;
               }
             }
           }
では、すべてのデータがどの群に属するかを決定し、群のデータ数もカウントしています。

データが41 67 34 0 69 24 78 58 62 64の場合で動きを追ってみましょう。
この場合最大値が78、最小値が0ですから、分類幅は(78−0)÷4=19.5
i=0のとき、cn[i]=0;からcn[0]は0と初期化されます。そして、
           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]++;
              }
            }
は、
           for(j=0;j<n;j++){
              if(p[j]>max-(0+1)*hb && p[j]<=max-0*hb){
                a[i][cn[i]]=p[j];
                cn[i]++;
              }
           }
により、
           for(j=0;j<n;j++){
              if(p[j]>max-hb && p[j]<=max){
                a[i][cn[i]]=p[j];
                cn[i]++;
              }
           }
となり、p[j]が78以下で、58.5より大きいなら第1群a[0]に入れていきます。
41 67 34 0 69 24 78 58 62 64の内、41 67 34 0 69 24 78 58 62 64ピンクが該当します。
ですから
                a[i][cn[i]]=p[j];
                cn[i]++;
によって、
(cn[i]=0;からcn[0]=0であったことに注意)a[0][0]=67、cn[0]=1→a[0][1]=69、cn[0]=2→a[0][2]=78、cn[0]=3→a[0][3]=62、cn[0]=4a[0][4]=64、cn[0]=5
(cn[0]=5は使用されないが、第1群のデータ数が5個であること示している。
データの最後がa[0][4]=64であり、5と1個ずれるのは添え字が0から始まることによる。)
と動いていきます。
では、皆さんi=1、i=2、i=3の場合でトレース(コンピュータの動きを追うこと)してみましょう。

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



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