基数ソートは非比較整数ソート アルゴリズムであり、その原理は、整数を桁数に応じて異なる数値に分割し、各桁を個別に比較することです。 整数は特定の形式の文字列 (名前や日付など) や浮動小数点数も表すことができるため、基数ソートは整数に限定されません。
最後に具体例として、JAVA、C、C++の実装例を挙げます。
1. 基数ソートvsカウントソートvsバケットソート
これら 3 つの並べ替えアルゴリズムはすべてバケットの概念を使用しますが、バケットの使用には明らかな違いがあります。
基数ソート: バケットはキー値の各桁に従って割り当てられます。
カウントソート: 各バケットには単一のキー値のみが保存されます。
バケットの並べ替え: 各バケットには特定の範囲の値が保存されます。
2. LSD 基数ソートアニメーションのデモンストレーション
実装例
JAVA言語の実装例
/**
* 基数ソート
*/
public class RadixSort implements IArraySort {
@Override
public int[] sort(int[] sourceArray) throws Exception {
// arr をコピー
int[] arr = Arrays.copyOf(sourceArray, sourceArray.length);
int maxDigit = getMaxDigit(arr);
return radixSort(arr, maxDigit);
}
/**
* 一番高い位数をとる
*/
private int getMaxDigit(int[] arr) {
int maxValue = getMaxValue(arr);
return getNumLenght(maxValue);
}
private int getMaxValue(int[] arr) {
int maxValue = arr[0];
for (int value : arr) {
if (maxValue < value) {
maxValue = value;
}
}
return maxValue;
}
protected int getNumLenght(long num) {
if (num == 0) {
return 1;
}
int lenght = 0;
for (long temp = num; temp != 0; temp /= 10) {
lenght++;
}
return lenght;
}
private int[] radixSort(int[] arr, int maxDigit) {
int mod = 10;
int dev = 1;
for (int i = 0; i < maxDigit; i++, dev *= 10, mod *= 10) {
// マイナスの場合を考える,ここでキューの数を 2 倍にします, [0-9]はマイナスの数値に対応,[10-19]はプラスの数値に対応 (bucket + 10)
int[][] counter = new int[mod * 2][0];
for (int j = 0; j < arr.length; j++) {
int bucket = ((arr[j] % mod) / dev) + mod;
counter[bucket] = arrayAppend(counter[bucket], arr[j]);
}
int pos = 0;
for (int[] bucket : counter) {
for (int value : bucket) {
arr[pos++] = value;
}
}
}
return arr;
}
private int[] arrayAppend(int[] arr, int value) {
arr = Arrays.copyOf(arr, arr.length + 1);
arr[arr.length - 1] = value;
return arr;
}
}
C言語の実装例
#include<stdio.h>
#define MAX 20
//#define SHOWPASS
#define BASE 10
void print(int *a, int n) {
int i;
for (i = 0; i < n; i++) {
printf("%d\t", a[i]);
}
}
void radixsort(int *a, int n) {
int i, b[MAX], m = a[0], exp = 1;
for (i = 1; i < n; i++) {
if (a[i] > m) {
m = a[i];
}
}
while (m / exp > 0) {
int bucket[BASE] = { 0 };
for (i = 0; i < n; i++) {
bucket[(a[i] / exp) % BASE]++;
}
for (i = 1; i < BASE; i++) {
bucket[i] += bucket[i - 1];
}
for (i = n - 1; i >= 0; i--) {
b[--bucket[(a[i] / exp) % BASE]] = a[i];
}
for (i = 0; i < n; i++) {
a[i] = b[i];
}
exp *= BASE;
#ifdef SHOWPASS
printf("\nPASS : ");
print(a, n);
#endif
}
}
int main() {
int arr[MAX];
int i, n;
printf("Enter total elements (n <= %d) : ", MAX);
scanf("%d", &n);
n = n < MAX ? n : MAX;
printf("Enter %d Elements : ", n);
for (i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}
printf("\nARRAY : ");
print(&arr[0], n);
radixsort(&arr[0], n);
printf("\nSORTED : ");
print(&arr[0], n);
printf("\n");
return 0;
}
C++言語の実装例
int maxbit(int data[], int n) //データの最大桁数を求める補助機能
{
int maxData = data[0]; ///< 最大数
/// 最初に最大の数値を見つけてから、その桁数を見つけます。これにより、各数値の桁数を順番に判断することが少し最適化されます。
for (int i = 1; i < n; ++i)
{
if (maxData < data[i])
maxData = data[i];
}
int d = 1;
int p = 10;
while (maxData >= p)
{
//p *= 10; // Maybe overflow
maxData /= 10;
++d;
}
return d;
/* int d = 1; //最大の桁数を保存する
int p = 10;
for(int i = 0; i < n; ++i)
{
while(data[i] >= p)
{
p *= 10;
++d;
}
}
return d;*/
}
void radixsort(int data[], int n) //基数ソート
{
int d = maxbit(data, n);
int *tmp = new int[n];
int *count = new int[10]; //カウンター
int i, j, k;
int radix = 1;
for(i = 1; i <= d; i++) //d回のソートを行う
{
for(j = 0; j < 10; j++)
count[j] = 0; //各割り当ての前にカウンタをクリアする
for(j = 0; j < n; j++)
{
k = (data[j] / radix) % 10; //各バケット内のレコードの数を数える
count[k]++;
}
for(j = 1; j < 10; j++)
count[j] = count[j - 1] + count[j]; //tmp 内の位置を各バケットに順番に割り当てる
for(j = n - 1; j >= 0; j--) //バケット内のすべてのレコードを順番に tmp に収集する
{
k = (data[j] / radix) % 10;
tmp[count[k] - 1] = data[j];
count[k]--;
}
for(j = 0; j < n; j++) //一時配列の内容をデータにコピーする
data[j] = tmp[j];
radix = radix * 10;
}
delete []tmp;
delete []count;
}
以上はアルゴリズム:基数ソートと、プログラミング言語JAVA、C、C++の実装例も含めて説明しました。
参考:
https://zh.wikipedia.org/wiki/%E5%9F%BA%E6%95%B0%E6%8E%92%E5%BA%8F
コメントを残す