| 导读 | 基数排序是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。 |
1. 基数排序 vs 计数排序 vs 桶排序
基数排序有两种方法:
这三种排序算法都利用了桶的概念,但对桶的使用方法上有明显差异:
- 基数排序:根据键值的每位数字来分配桶;
- 计数排序:每个桶只存储单一键值;
- 桶排序:每个桶存储一定范围的数值;
2. LSD 基数排序动图演示
代码实现:
JavaScript
实例
//LSD Radix Sort
var counter = [];
function radixSort(arr, maxDigit) {
var mod = 10;
var dev = 1;
for (var i = 0; i < maxdigit;="" i++,="" dev="" *="10," mod="" *="10)" {="" for(var="" j="0;" j="">< arr.length;="" j++)="" {="" var="" bucket="parseInt((arr[j]" %="" mod)="" dev);="" if(counter[bucket]="=null)" {="" counter[bucket]="[];" }="" counter[bucket].push(arr[j]);="" }="" var="" pos="0;" for(var="" j="0;" j="">< counter.length;="" j++)="" {="" var="" value="null;" if(counter[j]!="null)" {="" while="" ((value="counter[j].shift())" !="null)" {="" arr[pos++]="value;" }="" }="" }="" }="" return="" arr;="">
Java
实例
/**
* 基数排序
* 考虑负数的情况还可以参考: https://code.i-harness.com/zh-CN/q/e98fa9
*/
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)" {="" 考虑负数的情况,这里扩展一倍队列数,其中="" [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;="" }="" *="" *="" 自动扩容,并保存数据="" *="" *="" @param="" arr="" *="" @param="" value="" */="" private="" int[]="" arrayappend(int[]="" arr,="" int="" value)="" {="" arr="Arrays.copyOf(arr," arr.length="" +="" 1);="" arr[arr.length="" -="" 1]="value;" return="" arr;="" }="">
PHP
实例
function radixSort($arr, $maxDigit = null)
{
if ($maxDigit === null) {
$maxDigit = max($arr);
}
$counter = [];
for ($i = 0; $i < $maxdigit;="" $i++)="" {="" for="" ($j="0;" $j="">< count($arr);="" $j++)="" {="" preg_match_all('/\d/',="" (string)="" $arr[$j],="" $matches);="" $numarr="$matches[0];" $lentmp="count($numArr);" $bucket="array_key_exists($lenTmp" -="" $i="" -="" 1,="" $numarr)="" intval($numarr[$lentmp="" -="" $i="" -="" 1])="" :="" 0;="" if="" (!array_key_exists($bucket,="" $counter))="" {="" $counter[$bucket]="[];" }="" $counter[$bucket][]="$arr[$j];" }="" $pos="0;" for="" ($j="0;" $j="">< count($counter);="" $j++)="" {="" $value="null;" if="" ($counter[$j]="" !="=" null)="" {="" while="" (($value="array_shift($counter[$j]))" !="=" null)="" {="" $arr[$pos++]="$value;" }="" }="" }="" }="" return="" $arr;="">
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中="" data[j]="tmp[j];" radix="radix" *="" 10;="" }="" delete="" []tmp;="" delete="" []count;="">
C
实例
#include#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;="">
Lua
实例
-- 获取表中位数
local maxBit = function (tt)
local weight = 10; -- 十進制
local bit = 1;
for k, v in pairs(tt) do
while v >= weight do
weight = weight * 10;
bit = bit + 1;
end
end
return bit;
end
-- 基数排序
local radixSort = function (tt)
local maxbit = maxBit(tt);
local bucket = {};
local temp = {};
local radix = 1;
for i = 1, maxbit do
for j = 1, 10 do
bucket[j] = 0; --- 清空桶
end
for k, v in pairs(tt) do
local remainder = math.floor((v / radix)) % 10 + 1;
bucket[remainder] = bucket[remainder] + 1; -- 每個桶數量自動增加1
end
for j = 2, 10 do
bucket[j] = bucket[j - 1] + bucket[j]; -- 每个桶的数量 = 以前桶数量和 + 自个数量
end
-- 按照桶的位置,排序--这个是桶式排序,必须使用倒序,因为排序方法是从小到大,顺序下来,会出现大的在小的上面清空。
for k = #tt, 1, -1 do
local remainder = math.floor((tt[k] / radix)) % 10 + 1;
temp[bucket[remainder]] = tt[k];
bucket[remainder] = bucket[remainder] - 1;
end
for k, v in pairs(temp) do
tt[k] = v;
end
radix = radix * 10;
end
end;
达?矢抾哆拉?