什么是基数排序?
以下内容来自百度
基数排序(radix sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)或bin
sort,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用,基数排序法是属于稳定性的排序,其时间复杂度为O
(nlogm),其中r为所采取的基数,而m为堆数,在某些时候,基数排序法的效率高于其它的稳定性排序法。
基数排序使用桶每一位分别排序后再组合起来(对于每一位使用桶排)
看个图就懂了
我们要先搞懂基数的概念:基数是你排序使用的桶的大小。比如图上用的桶是从 0 − 9 0-9 0−9 也就是 10 10 10 的大小,我们的基数就是 10 10 10。
实现
基数排序共有 4 4 4 步:
- 计算每一个数的位数。
- 计算出当前排序的那一位的值,这里我们有一个公式:设当前数为 n n n 要求的位数为 k k k (个位为 0 0 0)则有 a n s w e r = ( n ÷ 基 数 k ) % 基数 answer=(n \div 基数^k) \% 基数 answer=(n÷基数k)%基数 。
- 将处理完的一位数所代表的下标加入桶,本人用的是 v e c t o r vector vector
- 将桶中排好序的数据重新加入原数组
第一部代码
for(int j=0;j<n;j++) wsa[j]=ws(a[j]);//ws函数用于计算位数
w s ws ws 函数
int ws(int k){
int ans=0;
while(k){
ans++;
k/=10;
}
return ans;
}
第二部分代码
for(int j=0;j<n;j++){
w[j]=0;
if(wsa[j]<i+1) continue;//需要特判这一位是否存在
w[j]=(a[j]/ten[i])%10;//记录当前位的值;
}
第三部分代码
for(int j=0;j<n;j++){//vector
b[w[j]].push_back(j);//加入桶
//if(w[j]==0) cout<<j<<endl;//调试
}
第四部分代码
int cnt=0;
for(int j=0;j<10;j++){
for(int k=0;k<b[j].size();k++){//重新开一个数组,避免覆盖
c[cnt]=a[b[j][k]];//处理完放回原数组;
cnt++;
}
while(b[j].size()) b[j].pop_back();
}
for(int j=0;j<n;j++) a[j]=c[j];
完整代码
#include<bits/stdc++.h>
using namespace std;
int n,a[10005],mxws=1,c[10005];
int ten[10],w[10005],wsa[10005];
vector<int> b[10];
int ws(int k){
int ans=0;
while(k){
ans++;
k/=10;
}
return ans;
}
int main(){
cin>>n;
for(int i=0;i<n;i++){
cin>>a[i];
wsa[i]=ws(a[i]);
if(wsa[i]>mxws) mxws=wsa[i];//求最高位数
}
ten[0]=1;
for(int i=1;i<10;i++) ten[i]=ten[i-1]*10;//记录10^x
for(int i=0;i<mxws;i++){
for(int j=0;j<n;j++) wsa[j]=ws(a[j]);
for(int j=0;j<n;j++){
w[j]=0;
if(wsa[j]<i+1) continue;
w[j]=(a[j]/ten[i])%10;//记录当前位的值;
}
for(int j=0;j<n;j++){
b[w[j]].push_back(j);//加入桶
}
int cnt=0;
for(int j=0;j<10;j++){
for(int k=0;k<b[j].size();k++){
c[cnt]=a[b[j][k]];//处理完放回原数组;
cnt++;
}
while(b[j].size()) b[j].pop_back();
}
for(int j=0;j<n;j++) a[j]=c[j];
}
for(int i=0;i<n;i++) cout<<a[i]<<" ";
return 0;
}
附样例:
5
1 5 3 2 4
5
5 22 10 6 78
总结
基数排序的时间复杂度比较抽象,要看你的基数选的是多少,比如我的代码的复杂度就是 O(10N)
对于用快速排序超时,用桶排序超空间的排序题很有用
最后求关 (^o^)