若对一个大整数序列进行排序操作,设序列中元素个数为 n,最大元素在十进制表示下的长度为 m,则快速排序的时间复杂度为 O(nmlog2n),此时对任意两个数的比对时间占 O(m)。在这里,对任意两个整型数的比较不再是常数时间复杂度的了。
但这时,我们可以发现相对于基于比较的排序而言,非基于比较的排序的优势显现出来了。尽管对于鸽巢排序、计数排序而言庞大的空间消耗使我们放弃了使用它们的可能,但时间复杂度和空间复杂度都为 O(nm) 的基数排序确实可以让我们的排序更快。事实上,就算是对于整型数而言,基数排序的时间复杂度和空间复杂度也都是 O(n) 的,只是常数略大而已。
基数排序是 m 次计数排序的结果。在每次的计数排序中,这些数以当前所设定的比对关键字为第一关键字,以这些数原来的位置为第二关键字排序,时间复杂度为 O(n),空间复杂度为 O(nm)。所以,计数排序是稳定的排序。这为基数排序的实施提供了可能。
对于一次基数排序操作,我们将其分解为 m+1 个状态,记为第 0 到第 m 个状态,第 i 个状态表示后 i 位有序且稳定的排序结果,即以后 i 位的值作为第一关键字,以这些数上一次排序后的位置作为第二关键字的排序结果。特别的,第 0 个状态为起始状态。对于第 i 个状态,我们可以通过将第 i-1 个状态的序列对其右起第 i 位进行计数排序得到。第 m 个状态即为最终排序的结果。由归纳法可知,这个排序方法是正确的。
代码如下:
#include"iostream"
#include"stdio.h"
#include"string.h"
#define MAX_M (0xF)
#define MAX_N (100005)
using namespace std;
char temp[MAX_M];
int array[MAX_N][MAX_M],length[MAX_N],n,temp_array[MAX_N][MAX_M],temp_length[MAX_N];
void countsort(int num)
{
int sum[0xF];
memset(sum,0,sizeof(sum));
for(int i=1;i<=n;i++)
sum[array[i][num]]++;
for(int i=1;i<10;i++)
sum[i]+=sum[i-1];
for(int i=n;i>0;i--)
{
for(int j=0;j<length[i];j++)
temp_array[sum[array[i][num]]][j]=array[i][j];
temp_length[sum[array[i][num]]--]=length[i];
}
memset(array,0,sizeof(array));
for(int i=1;i<=n;i++)
{
for(int j=0;j<temp_length[i];j++)
array[i][j]=temp_array[i][j];
length[i]=temp_length[i];
}
}
int main()
{
memset(array,0,sizeof(array));
int m=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
cin>>temp;
length[i]=strlen(temp);
if(length[i]>m)
m=length[i];
for(int j=0;j<length[i];j++)
array[i][j]=temp[length[i]-j-1]-'0';
}
for(int i=0;i<m;i++)
countsort(i);
for(int i=1;i<=n;i++)
{
for(int j=length[i]-1;j>=0;j--)
printf("%d",array[i][j]);
if(i<n)
printf(" ");
}
return 0;
}