基数排序(桶排序)
基数排序(Radix Sort)又称多关键码排序,它通过一些键值,将序列中的元素分配至相应的桶中,以达到排序的目的,它是一种稳定的排序算法,其时间复杂度为O(M*N),M为数据位数,N为数据个数,空间复杂度为O(N)。
基数排序又分为低关键码优先和高关键码优先两种。
我们先来研究第一种:
低关键码优先排序
步骤:
1.首先根据个位数的数值,将所有数据分配到0~9号桶中
2.再将所有桶中的数据按桶号由大到小依次重新收集起来
3.再将十位百位以及更高位按照同样的方式分配并收集
代码如下:
//获取一组序列中最大元素的位数
int GetBitNum(int array[], int size)
{
int i = 0;
int count = 0;
int max = array[0];
for (i=1; i < size; ++i)
{
if (array[i]>max)
max = array[i];
}
while (max)
{
count++;
max /= 10;
}
return count;
}
void RadixSortLSD(int array[], int size)
{
//开辟空间用来收集数据
int *bucket = (int*)malloc(sizeof(array[0])*size);
if (NULL == bucket)
return;
int i = 0;
int bitNum = GetBitNum(array, size);
int bitidx = 0;
int radix = 1;
//循环最大元素的位数次
for (; bitidx < bitNum; ++bitidx)
{
//统计每个桶中的元素个数
int count[10] = { 0 };
int startAddr[10] = { 0 };
for (i=0; i < size; ++i)
{
count[array[i]/radix % 10]++;
}
//计算每个桶的起始位置
for (i = 1; i < 10; ++i)
{
startAddr[i] = startAddr[i - 1] + count[i - 1];
}
//将元素放入对应桶中
for (i = 0; i < size; ++i)
{
int bucketNo = array[i] / radix % 10;
bucket[startAddr[bucketNo]++] = array[i];
}
//对元素进行回收
memcpy(array, bucket, sizeof(array[0])*size);
radix *= 10;
}
}
测试用例:
int main()
{
int array[] = { 203,156,369,420,671,523,188,198,453,120,479 };
PrintArray(array, sizeof(array) / sizeof(array[0]));
RadixSortLSD(array, sizeof(array) / sizeof(array[0]));
PrintArray(array, sizeof(array) / sizeof(array[0]));
}
运行结果:
接下来看第二种
高关键码优先
与低关键码优先方法类似,但是必须用递归实现
先将高位按照以上方式进行归位,再将每个桶中的元素按照次高位由大到小进行归位,以此类推直至最低位
代码如下:
void _RadixSortMSD(int array[], int left, int right,int *bucket, int bit)
{
if (bit < 0)
return;
int radix = pow((double)10, bit);//求x的y次方
int count[10] = { 0 };
int startAddr[10] = { 0 };
int i = 0;
//计算每个桶中有效元素的个数
for (i = left; i < right; ++i)
{
count[array[i] / radix%10]++;
}
//求每个桶的起始位置
for (i = 1; i < 10; ++i)
{
startAddr[i] = startAddr[i - 1] + count[i - 1];
}
//将元素们放入桶中对应位置
for (i = left; i < right; ++i)
{
int bucketNo = array[i] / radix%10;
bucket[startAddr[bucketNo]++] = array[i];
}
//回收桶中元素
memcpy(array + left, bucket, sizeof(array[0])*(right - left));
//再将每个桶中的元素作为一个序列进行桶排序
for (i = 0; i < 10; ++i)
{
int begin = startAddr[i] - count[i];
int end = startAddr[i];
_RadixSortMSD(array, begin, end, bucket, bit - 1);
}
}
void RadixSortMSD(int array[], int size)
{
int *bucket = (int *)malloc(sizeof(array[0])*size);
if (NULL == bucket)
return;
_RadixSortMSD(array, 0, size,bucket, GetBitNum(array, size) - 1);
free(bucket);
}
测试用例:
int main()
{
int array[] = { 203,156,369,420,671,523,188,198,453,120,479 };
PrintArray(array, sizeof(array) / sizeof(array[0]));
RadixSortMSD(array, sizeof(array) / sizeof(array[0]));
PrintArray(array, sizeof(array) / sizeof(array[0]));
}
运行结果: