サイトマップ / C言語講座>出入り口>総目次>目次:ソート>ビンソート
/* 今日はビンソートについて、学びます。ビン ( bin ) とは、”セサミストリート”でよく見かけるゴミなどを入れておく大きな容器のことです。
ビンソートは、整数の配列で、かつ、配列の要素の値の取る範囲が、前もってわかっている時にしか使えません。例えば、要素数が40で、0から99までの正の整数を取る配列、x[ ] があるとします。値は互いに等しくないとします。
作業用の配列として、要素が100の int 型の配列を用意します。この配列が、ビンソートにおけるデータを一時的にしまう"ビン" になります。Bin[ ] の各要素は、0 に初期化しておきます (注1、2) 。
x[ ] の要素を順番に読んで、Bin[ その値 ] を1インクリメントします。この作業を全ての x[ ] の要素について行った後、Bin[ ] の要素を順番に読んで、Bin[ ] の値が0でなければ、x[ ] に書き戻します。
ビンソートは、ソート対象のデータに制約がありますが、データのばらつきかたに影響されない、高速なソートです。
注1:データがないという意味で、- 1 に初期化する場合もあります。
注2:Bin[ ] は外部変数なので、コンパイル時に、0に初期化されてますが、ビンソートを複数回呼び出すような変更を予想して、呼び出される度に初期化したほうが、安全でしょう。
*/
#include <stdio.h>
#define MAX_DATA 100
int Bin[MAX_DATA]; /* 作業用配列 */
void BinSort(int x[ ], int n);
void ShowData(int x[ ], int n);
void main(void);
/* ビンソートを行う */
void BinSort(int x[ ], int n)
{
int i, j;
if (n > MAX_DATA) {
printf("データが多すぎます!\n");
return;
}
else {
for (i = 0; i < MAX_DATA; i++)
Bin[i] = 0; /* 作業用配列の初期化 */
for (i = 0; i < n; i++) /* x[i] の値の */
Bin[x[i]]++; /* Bin[ ] の要素の値を */
/* インクリメント */
j = 0; /* x[ ] の添字として使用 */
for (i = 0; i < MAX_DATA ; i++)
if (Bin[i]) /* 0でなければ */
x[j++] = i; /* 書き戻す */
}
}
/* 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[MAX_DATA] = {89, 1, 78, 58, 48, 18, 9, 21, 56, 11,
62, 23, 38, 96, 4, 45, 73,14, 30, 27,
6, 35, 2, 25, 69, 41, 8, 51, 0, 32,
98, 12, 33, 72, 19, 52, 28, 86, 17, 99
};
int n = 40; /* ソートするデータの数 */
/* ソート前のデータを表示 */
printf("ソート前:\n");
ShowData(x, n);
printf("\n");
BinSort(x, n);
/* ソート後のデータを表示 */
printf("\n\nAソート後:\n");
ShowData(x, n);
}
|
/* ビンソートの欠点として、配列の取りうる値の範囲が広いと、メモリ効率が悪くなり、更に広いと、作業用の配列を事実上取れなくなります。例えば、0から100,000 までの値を取りうる、要素数 10 の配列のソートなどが、これに当たります。
実は、以前に、ビンソートの文字版について学んでいます( ファイル中の英文字の出現頻度を調べる ) 。これは char のサイズの数の要素を持った配列を用意して、ファイルの中で現れるアルファベットの値を添字として使い、その配列の要素をインクリメントして、アルファベットの出現頻度を調べるプログラムです。 */
/* (C) 2000- YFプロ. All Rights Reserved. */ 提供:C言語講座−それ自体コンパイルできる教材を使った講座です−