一、算法简介
基数排序属于非比较型排序 ,依靠分配与收集思想完成排序,不依靠元素大小比较。原理:将整数按个位、十位、百位 依次排序,从低位到高位逐轮稳定排序,最终实现整体有序,常用 LSD 低位优先 方式。
时间复杂度:\(O(d(n+r))\) d 为最大位数,r 为基数
空间复杂度:\(O(n+r)\)
稳定性:稳定排序
适用场景:整数、手机号、日期等固定位数数据排序
二、排序思路
- 找出数组中最大值,确定最大数字位数,决定排序轮数
- 以 10 为基数,依次对个位、十位、百位进行排序
- 每一轮使用计数排序思想统计频次,完成一轮位次排序
- 逐位循环,全部位数排完即整体有序
三、C++ 完整实现代码
cpp
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// 获取数组最大值
int getMax(vector<int>& arr)
{
int maxVal = arr[0];
for (int num : arr)
{
if (num > maxVal)
maxVal = num;
}
return maxVal;
}
// 基数排序 LSD 低位优先
void radixSort(vector<int>& arr)
{
if (arr.size() <= 1) return;
int maxNum = getMax(arr);
// exp 代表当前位数 1个位 10十位 100百位
int exp = 1;
while (maxNum / exp > 0)
{
vector<int> temp(arr.size());
// 0~9计数桶
vector<int> count(10, 0);
// 1.统计当前位数字出现次数
for (int i = 0; i < arr.size(); i++)
{
int digit = (arr[i] / exp) % 10;
count[digit]++;
}
// 2.累加次数,确定元素位置
for (int i = 1; i < 10; i++)
{
count[i] += count[i - 1];
}
// 3.倒序放入临时数组,保证排序稳定
for (int i = arr.size() - 1; i >= 0; i--)
{
int digit = (arr[i] / exp) % 10;
temp[count[digit] - 1] = arr[i];
count[digit]--;
}
// 4.临时数组覆盖原数组
arr = temp;
// 进位处理下一位
exp *= 10;
}
}
// 打印数组
void printArr(vector<int>& arr)
{
for (int val : arr)
{
cout << val << " ";
}
cout << endl;
}
int main()
{
vector<int> nums = {53, 3, 542, 748, 14, 214, 154, 63, 616};
cout << "排序前:";
printArr(nums);
radixSort(nums);
cout << "排序后:";
printArr(nums);
return 0;
}
四、代码核心解析
-
getMax 函数遍历数组拿到最大值,用来判断需要排序多少位数字。
-
逐位排序逻辑
-
(arr[i]/exp)%10取出当前位次数字 -
count 数组统计 0-9 每个数字出现次数
-
倒序遍历赋值,保证稳定排序,不打乱前面低位排好的顺序
-
位数递进
exp *= 10依次切换个位、十位、百位,直到所有位数排序完成。
五、优缺点总结
优点
- 线性排序效率高,数据量大时远超冒泡、插入排序
- 排序稳定,相同数值相对位置不变
- 逻辑简单,容易手写实现
缺点
- 仅适合整数类数据排序,使用场景受限
- 存在额外数组开销,占用内存
- 数字位数极大时,排序轮数变多,效率下降
六、使用场景
- 海量手机号、QQ 号、学号排序
- 统计类大数据整数排序
- 笔试面试手写稳定排序优先选择基数排序