基数排序属于“分配式排序”,又称“桶子法”。它是通过键值的信息,将要排序的元素分配至某些“桶”中,以达到排序的作用。基数排序属于稳定性排序。
时间复杂度
基数排序的时间复杂度为O(nlog(r)m),其中r为所采取的基数,而m为堆数。
基本原理
将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。
方法
最高位优先法,简称MSD法:先按k1排序分组,同一组中记录,关键码k1相等,再对各组按k2排序分成子组,之后,对后面的关键码继续这样的排序分组,直到按最次位关键码kd对各子组排序后。再将各组连接起来,便得到一个有序序列。
最低位优先法,简称LSD法:先从kd开始排序,再对kd-1进行排序,依次重复,直到对k1排序后便得到一个有序序列。
实例
按LSD方法,假设有一个数组如下:
73,22,93,43,55,14,28,65,39,81
第一步:首先根据个位数的数值,将它们依次分配到0-9个桶中:
0号桶:
1号桶:81
2号桶:22
3号桶:73,93,43
4号桶:14
5号桶:55,65
6号桶:
7号桶:
8号桶:28
9号桶:39
第二步:将桶子里的数值串起来,称为以下数列:
81,22,73,93,43,14,55,65,28,39
接着根据十位数来分配:
0号桶:
1号桶:14
2号桶:22,28
3号桶:39
4号桶:43
5号桶:55
6号桶:65
7号桶:73
8号桶:81
9号桶:93
第三步:将桶子里的数值重新串起来成为以下数列:
14, 22, 28, 39, 43, 55, 65, 73, 81, 93
这时候整个数列已经排序完毕;如果排序的对象有三位数以上,则持续进行以上的动作直至最高位数为止。
LSD的基数排序适用于位数小的数列,如果位数多的话,使用MSD的效率会比较好。MSD的方式与LSD相反,是由高位数为基底开始进行分配,但在分配之后并不马上合并回一个数组中,而是在每个“桶子”中建立“子桶”,将每个桶子中的数值按照下一数位的值分配到“子桶”中。在进行完最低位数的分配后再合并回单一的数组中。
下面是代码实现:
#include<stdio.h>
#include<iostream>
using namespace std;
int maxbit(int data[], int n) //辅助函数,求数据的最大位数
{
int d = 1; //保存最大的位数
int p = 10;
for (int i = 0; i < n; ++i)
{
while (data[i] >= p)
{
p *= 10;
++d;
}
}
return d;
}
int* 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;
}
return data;
delete[]tmp;
delete[]count;
}
int main()
{
const int n = 13;
int data[] = { 1,255,8,6,25,47,14,35,58,75,96,158,657 };
for (int i = 0; i < n; i++)
cout << data[i] << " ";
cout << endl;
int *d = radixsort(data,n);
for (int i = 0; i < n; i++)
cout << d[i] << " ";
cout << endl;
system("pause");
}