第 13 回 - ソーティング(2)

[6/9, 2006 H.Aman]
67x27(1669bytes)   67x27(1669bytes) 【課題 1】

例題 1

5 人の生年月日(年,月,日)を読み込み,1 人ずつ構造体 birthday の配列に格納しなさい. そして,その 5 人を生まれた順に並び替えて表示しなさい.
なお,構造体 birthday の宣言は以下の通りとする:
 struct  birthday { 
   int  year;
   int  month;
   int  day;
 };

方針・アルゴリズム

基本は 前回の例題2 と同じである. データを読み込み,並べ替えを行い,順に出力すればよい. つまり,
  • struct birthday の配列(ここでは a とする)を用意する.
  • i の値を 0 〜 4 の範囲で変化させながら, a[i].year, a[i].month, a[i].day を読み込む.
  • n = 4 〜 1 の範囲(-1 していく)で以下を繰り返す(右端をずらす):
    • m = 0 と仮定( a[0] が最も若いと仮定 )する.
    • そして,i の値を 1 〜 4 の範囲で変化させながら, a[m] よりも a[i] の方が若ければ m ← i とする.
    • 最後に m < n なら a[m] と a[n] の値を交換する.
  • データを順に出力する.

コーディング例

     1	/*
     2	 * プログラミング演習 第 13 回
     3	 * [例題 1]
     4	 * (C) 2006 Hirohisa AMAN <aman@cs.ehime-u.ac.jp, aman@computer.org>
     5	 */
     6	#include <stdio.h>
     7	
     8	struct birthday {
     9	  int year;
    10	  int month;
    11	  int day;
    12	};
    13	
    14	int main(void){
    15	  struct birthday a[5], tmp;
    16	  int i, n, m, code_m, code_i;
    17	
    18	  /* a[i] を読み込む */
    19	  for ( i = 0; i < 5; i++ ){
    20	    printf("%d > ", i);
    21	    scanf("%d %d %d", &a[i].year, &a[i].month, &a[i].day);
    22	  }
    23	
    24	  for ( n = 4; n >= 0; n-- ){
    25	    m = 0;  /* a[0] が最も若いと仮定 */
    26	    for ( i = 1; i <= n; i++ ){
    27	      code_m = a[m].year * 10000 + a[m].month * 100 + a[m].day;
    28	      code_i = a[i].year * 10000 + a[i].month * 100 + a[i].day;
    29	      if ( code_m < code_i ){ 
    30		m = i;  /* 最大値の位置の更新 */
    31	      }
    32	    }
    33	    if ( m < n ){ /* a[m] と a[n] の値を交換 */
    34	      tmp = a[m];
    35	      a[m] = a[n];
    36	      a[n] = tmp;
    37	    }
    38	  }
    39	  
    40	  for ( i = 0; i < 5; i++ ){
    41	    printf("%d %d %d\n", a[i].year, a[i].month, a[i].day);
    42	  }
    43	
    44	  return 0;
    45	}
     
※左端の数字は行番号であり,ソースコードには含まれない点に注意!

コンパイル & 実行例

     $ gcc example13_1.c [Enter]
     $ ./a.out [Enter]
     0 > 1980 1 1 [Enter]
     1 > 1985 10 8 [Enter]
     2 > 1985 10 7 [Enter]
     3 > 1975 3 3 [Enter]
     4 > 1975 2 28 [Enter]
     1975 2 28
     1975 3 3
     1980 1 1
     1985 10 7
     1985 10 8
     

解説

基本として選択ソートをやっているだけであるため, プログラムの流れは 前回の例題2 と同じである.

唯一の違いは,データ型が int ではなく構造体 birthday になっているという点にある.
構造体は自作の型であるため, a[m] < a[i] というように 不等号を使った比較ができない. そこで,構造体の内容を 比較可能な数値に変換 してやることにする.

単純に考えれば,

  • 生まれた年が大きい方が若く,
  • 生まれた月が大きい方が若く,
  • 生まれた日が大きい方が若い.
もちろんこれら 3 つの項目に対応する if 文を 3 つ書いても間違いではないが,次のルールで整数に変換すれば 1 回の比較で済む:
2006 年 7 月 12 日   →   20060712
2006 年 1 月 1 日   →   20060101
2005 年 12 月 31 日   →   20051231
この変換は,それぞれ年を 10000 倍,月を 100 倍して日に足せばよい. 上のコーディング例の 27, 28 行目がこれにあたる:
    27	      code_m = a[m].year * 10000 + a[m].month * 100 + a[m].day;
    28	      code_i = a[i].year * 10000 + a[i].month * 100 + a[i].day;