サイトマップ / C言語講座出入り口総目次目次:ソート>基数ソート

青い直線

基数ソート

青い直線

[シェルソート]←このソース→[マージソート]

/* 基数ソート */

/* 今日は基数 ( Radix ) ソートについて、学びます。基数ソートでは、まず、1の位の数を見て、ソートします。結果はこのようになります。

    ソート前:12, 34, 91, 16, 83

    ソート後:91, 12, 83, 34, 16

上のソートの結果では、12 と 16 の振る舞いに注目して下さい。最初のソートで、当然ですが、12 の方が先頭に近くなっています。この関係が保たれたまま、2桁目の値でソートを行います。下記の結果が得られます。

    結果:12, 16, 34,  83, 91

ある桁をソートする時、その桁の数が同じものは、その前のソートの結果が保存されたままソートされます。この、前後関係が保たれたまま、次のソートが行われる点が、基数ソートの原理です。

次々回に扱うビンソートでは、ソートする配列の要素が少なく、取りうる値の範囲が広いと、メモリ効率が悪くなるという欠点があります。基数ソートでは、この点は問題になりません。しかし、整数しか扱えないという制約は、依然として存在します。

基数ソートのアルゴリズムは、古くから知られています。

ソースプログラムの説明

RadixSort( ) は、三つの引数を取ります。

    int x[ ]:ソート対象の配列
    int n:   配列要素の数
    int r:   基数を取り出す最大値

静的領域には、次の配列を宣言しておきます。

    rad[ ]:基数をしまう配列
    y[ ]:  作業用配列

x[ ] と rad[ ] と y[ ] のサイズは同じでなければなりません。

i の値を for ループの中で、0から n まで変化させて、下記の計算を行います。

    (x[i] / m) % 10

m の初期値は1なので、この計算をすると、x[i] の1の位の基数が求まります。これを配列 rad[i] に保存します。rad[ ] は x[ ] の基数の配列になります。

次の for ループの中で、rad[ ] の値の小さいものから順に取り出し、その添字と等しい x[ ] の要素を、y[ ] にコピーします。この時にソートが行われます。次いで、配列 y[ ] の値を配列 x[ ] にコピーし直します。

一連の操作を終わった所で、 m の値を10倍します。整数どおしの計算では、余りは切り捨てられます。 そこで、次の計算で、10の位の数を取り出すことができます。

    (x[i] /  m) % 10

以上の手順を m が r を越えない間繰り返せば、ソートが完成します。

以上のアルゴリズムをコードにしたのが、今回のソースプログラムです。

基数ソートはビンソートやバブルソートと同様に、データのばらつきかたの影響を受けません。 */

/* ここからソースプログラム */

#include  <stdio.h>

void RadixSort(int x[ ], int n, int r);
void ShowData(int x[ ], int n);
void main(void);

#define NUM_DATA 10

static int rad[NUM_DATA];    /* 基数をしまう配列  */
static int y[NUM_DATA];      /* 作業用配列 */

  /* 基数ソートを行う */
void RadixSort(int x[ ], int n, int r)  /* x[ ]:ソートするデータ */
{                                       /* n:データの数 */
    int i, j, k;                        /* r:基数を取り出す最大値 */
    int m = 1;                          /* 基数を取り出す桁 */

    while (m <= r) {
        for (i = 0; i < n; i++)
            rad[i] = (x[i] / m) % 10;   /* 基数を取り出し rad[i] に保存 */

        k = 0;                          /* 配列の添字として使う */
        for (i = 0; i <= 9; i++)        /* 基数は 0 から 9 */
            for (j = 0; j < n; j++)
                if (rad[j] == i)        /* 基数の小さいものから */
                    y[k++] = x[j];      /* y[ ] にコピー */

        for (i = 0; i < n; i++)
            x[i] = y[i];                /* x[ ] にコピーし直す */
	
          /*  途中経過を表示  */
        printf("\nソート中:\n");
        ShowData(x, n);
				
        m *= 10;                        /*  基数を取り出す桁を一つ上げる */
    }
}

  /* n 個のデータを表示する */
void ShowData(int x[ ], int n)
{
    int i;

    for (i = 0; i < n ; i++)
        printf("%d\t", x[i]);
}

void main(void)
{      /* ソートするデータ */
    int x[NUM_DATA] = { 5489, 1473, 7853, 1058, 9448,
                        1118, 7979, 2163, 1856, 3117
    };
    int n = 10;        /* ソートするデータ数 */
    int r = 1000;      /* ソートするデータから取り出す基数の上限 */
	
      /* ソート前のデータを表示 */
    printf("ソート前:\n");
    ShowData(x, n);
    printf("\n");

    RadixSort(x, n, r);
		
      /* ソート後のデータを表示 */
    printf("\n\nソート後:\n");
    ShowData(x, n);
}

/* ここまでソースプログラム */

/* プログラムを実行すると、ソートの途中経過も表示されます。基数ソートの進行の様子を確認して下さい。 */

[シェルソート]←このソース→[マージソート]

青い直線

/* (C) 2000- YFプロ. All Rights Reserved. */    提供:C言語講座−それ自体コンパイルできる教材を使った講座です−

青い直線

サイトマップ / C言語講座出入り口総目次目次:ソート>基数ソート