基本思想
将待排数据中的每组关键字依次进行桶分配。
实质是一种考虑多关键字的排序算法。
MSD:
假设我们有一些二元组(a,b),如果我们对a为首要关键字,b为次要关键字进行排序。就称为MSD
我们按照首要关键字排序,把相同的分到一起,这样我们就有了若干个桶,然后再按照次要关键字分别对每一堆进行排序。最后合并,这就是MSD
LSD
从最低有效关键字开始排序。具体看下面:
具体示例:
278、109、063、930、589、184、505、269、008、083
我们将每个数值的个位,十位,百位分成三个关键字: 278 -> k1(个位)=8,k2(十位)=7,k3=(百位)=2。
然后从最低位个位开始(LSD),对所有数据的k1关键字进行桶分配(因为,每个数字都是 0-9的,因此桶大小为10),再依次输出桶中的数据得到下面的序列。
实际我们要先建立桶(LinkedList):(根据最低位)
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
930 | 063 | 184 | 505 | 278 | 109 | ||||
083 | 008 | 589 | |||||||
269 |
输出为:
930、063、083、184、505、278、008、109、589、269
再对上面的序列接着进行针对k2的桶分配:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
505 | 930 | 063 | 278 | 083 | |||||
008 | 269 | 184 | |||||||
109 | 589 |
输出序列为:
505、008、109、930、063、269、278、083、184、589
最后针对k3的桶分配,(最高位)
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
008 | 109 | 269 | 505 | 930 | |||||
063 | 184 | 278 | 589 | ||||||
083 |
输出序列为:
008、063、083、109、184、269、278、505、589、930
LSD算法实现
public int getDigit(int x,int d){
int a[]={1,10,100,1000};
return (x/a[d])%10;
}
//按照数据来定义k进制/每位出现的可能性
//3位数,还是需要观察,这对输入数据有要求,我要检测这个数据是多少位?
public void Sort(int[] A){
int N=A.length, k=10,P=3; //需要观察数据
int[] tmp=new int[N];
int[] count=new int[k];//桶 初始化值应该为0
for(int d=0;d<P;d++){
//每次循环要对count清空
for(int j=0;j<N;j++)
count[j]=0;
//统计入每个桶的元素个数
for(int j=0;j<N;j++){
int i=getDigit(A[j],d);
count[i]++;
}
//算下标, 算出真正对应 A数组的下标
for(int j=1;j<k;j++){
count[j]+=count[j-1];
}
//数据依次转入桶中
//必须倒序存进来才对
for(int j=N-1;j>=0;j--){
int i=getDigit(A[j],d);
//index = count[i]-1;
if(count[i]<1)
continue;
tmp[count[i]-1]=A[j];//放入临时数组
count[i]--; //对应桶的数据索引减一
}
for(int j=0;j<N;j++){
A[j]=tmp[j];
}
}
}
基数排序还可以用于多关键字排序
例如对扑克牌排序的问题
主位优先排序MSD
思想
我们可以根据花色建立4个桶,然后将52张牌分别放入这4个桶,然后对这4个桶分别排序。 当然我们可能需要调用快排或者其他比较排序算法。
最后把它们合并就可以了。
LSD解决
为次关键字也就是面值建立13个桶,结果因为扑克牌就只有13种值,故其实我们分配到13个桶之后就已经排好序了。
实质来说,当主位的基数个数大于次位的时候,主位优先更快。
效率分析
设元素个数为N,整数进制为B,LSD的趟数为P(也就是我们的位数),则最坏的时间复杂度是:
O(P(N+B))
因为每一趟我们要收集分配这些数到我们的桶中,其实对于每一趟来说,我们做的事情和桶排序是一样的。(因为我们不需要对桶里面的内容进行排序,而仅仅是分配)
基数排序的空间复杂度是
O(M+N) M为桶的数量。