一、算法思想
基数排序是一种非比较型整数排序算法,其原理是将众多数字按位分隔后进行排序。
实现步骤:
1.将所有待比较的数字(正整数)统一为同一长度,位数不够的数字前面补0;
2.按照从个位,十位,百位······从低到高的顺序进行排序
3.完成从低位到高位的排序后,待排序数字也就完成了排序
具体举例说明:
初始化序列num{57, 123, 564, 32, 0, 56, 169, 5, 23, 11, 100}
将上述序列的数字按照个位数字进行排序,个位数字取值范围0-9,我们可以将其设置为数组用来存储序列中的数字,如下所示
然后我们将这些数字按照个位再取出来得到新的序列num_new{0, 100, 11, 32,123, 23, 564, 5, 56, 57, 169},下面按照十位,百位继续进行排序,结束后便是有序数列
动态效果示意图如下
用代码实现的思路:
1.计算出得到的序列中的位数最大的数字的位数,以便确定需要进行几次排序
2.创建取出任意数字任意位数的函数,用于对数字的排序
3.接下来便可以开始排序
C++代码如下:
#include <iostream>
#include <vector>
using namespace std;
int MaxBit(vector<int> input) //求出数组中最大数的位数
{
int max_num = input[0]; //默认最大数为第一个数字
for (int i = 0; i < input.size(); i++) //找出数组中的最大数
{
if (input[i] > max_num)
{
max_num = input[i];
}
}
int p = 0;
while (max_num > 0)
{
p++;
max_num /= 10; //每次除以10取整,即可去掉最低位
}
return p;
}
int GetNum(int num, int d) //取出所给数字的第d位数字
{
int p = 1;
while (d - 1 > 0)
{
p *= 10;
d--;
}
return num / p % 10;
}
vector<int> RadixSort(vector<int> input, int length) //基数排序
{
vector<int> bucket(length); //创建临时存放排序过程中的数据
vector<int> count(10); //创建按位计数的技术容器,即记录排序中按个位、十位...各个数的位置的个数
for (int d = 1; d <= MaxBit(input); d++) {
// 计数器清0
for (int i = 0; i < 10; i++) {
count[i] = 0;
}
// 统计各个桶中的个数
for (int i = 0; i < length; i++) {
count[GetNum(input[i], d)]++;
}
for (int i = 1; i < 10; i++) { //得到每个数应该放入bucket中的位置
count[i] += count[i - 1];
}
for (int i = length - 1; i >= 0; i--) { //采用倒序进行排序是为了不打乱已经排好的顺序
int k = GetNum(input[i], d);
bucket[count[k] - 1] = input[i];
count[k]--;
}
for (int j = 0; j < length; j++) // 临时数组复制到 input 中
{
input[j] = bucket[j];
}
}
return input;
}
int main()
{
int arr[] = { 50, 123, 543, 187, 49, 30, 0, 2, 11, 100 };
vector<int> test(arr, arr + sizeof(arr) / sizeof(arr[0]));
cout << "排序前:";
for (int i = 0; i < test.size(); i++) {
cout << test[i] << " ";
}
cout << endl;
vector<int> result = test;
result = RadixSort(result, result.size());
cout << "排序后:";
for (int i = 0; i < result.size(); i++) {
cout << result[i] << " ";
}
cout << endl;
system("pause");
}
运行结果:
关于
for (int i = 1; i < 10; i++) { //得到每个数应该放入bucket中的位置
count[i] += count[i - 1];
}
的解释:
bucket数组的长度为11,那么按照个位取出的数字应该如何放入bucket中呢?
我们发现:{0, 100, 11, 32,123, 23, 564, 5, 56, 57, 169}
例如:169应该放入下标为10的位置上,100应该放在下标为1的位置上,32应该放在下标为3的位置上…计算规则为,要放到bucket中数的前面有多少个元素,那么他就要被放置到下标为几的位置上
所以要将数据累加,所以有了后边
for (int i = length - 1; i >= 0; i--) { //采用倒序进行排序是为了不打乱已经排好的顺序
int k = GetNum(input[i], d);
bucket[count[k] - 1] = input[i];
count[k]--;
}
二、算法分析
1.时间复杂度
这个时间复杂度比较好计算:count * length;其中 count 为数组元素最高位数,length为元素个数;所以时间复杂度:O(n * d)
2.空间复杂度
空间复杂度是使用了两个临时的数组:10 + length;所以空间复杂度:O(n)
参考:
https://cuijiahua.com/blog/2018/01/algorithm_8.html
https://www.bilibili.com/video/BV1xz411i7Eb?from=search&seid=16588675175267367436