基数排序的主要思想:
基数排序又称"桶子法",他从低位开始将待排序的数按照这一位的值放到相应的编号为0到9的桶中。等到低位排完之后得到一个序列,再将这个序列按照次低位的大小进入相应的桶中。以此类推,直到将所有的位都排完之后,这组数就已经有序了。
例:
基数排序是一种非比较排序,它的时间复杂度是O(N*digit),其中digit是这组待排序中的最大的数的数量级,它的空间复杂度是O(N)。它是一种稳定的排序方法。
实现:
对于桶,我们最直观的想法就是用容器作为桶,将每一个桶的元素都放到一个容器中,这样虽然也能做,但是还是实现起来不是那么容易。我们可以参考稀疏矩阵的转置。例如对个位数的排序,我们开辟一个10元素大小的数组,将这10个大小的数组假想成10个桶,统计出每个桶中第一个元素在原数组中的起始位置。我们在建立一个与要排序的序列一样大辅助数组,然后根据每个桶中的起始位置将每个桶中的元素依次放到辅助数组中,之后再把辅助数组中的元素拷贝回原数组,这样一次排序就完成了。之后再按照同样的方法,再对高位进行排序。
代码实现:
int CountDigit(int* a, int n) //统计这组数中最大的数的数量级
{
int base = 10;
int digit = 1;
for (int i = 0; i < n; ++i)
{
while (a[i]>=base)
{
digit++;
base *= 10;
}
}
return digit;
}
void BaseSort(int *a,int n)
{
assert(a);
int digit = CountDigit(a,n);
int base = 1;
int *tmp = new int[n];
while (digit--)
{
int count[10] = { 0 }; //统计个位相同的数出现的次数
for (int i = 0; i < n; ++i)
{
int index = a[i]/base% 10;
count[index]++;
}
int start[10] = { 0 }; //统计个位相同的数在a中的起始位置
for (int i = 1; i < 10; i++)
start[i] = start[i - 1] + count[i - 1];
memset(tmp, 0, sizeof(int)*n);
for (int i = 0; i < n; i++)
{
int index = a[i]/base% 10;
tmp[start[index]++] = a[i];
}
for (int i = 0; i < n; i++)
a[i] = tmp[i];
base *= 10;
}
delete[] tmp;
}