概述
首先从多排序码排序开始介绍基数排序。以扑克牌排序为例。每张扑克牌有两个“排序码”:花色和面值。其有序关系为:
- 花色: ♣<♦<♥<♠
- 面值: 2<3<4<5<6<7<8<9<10<J<Q<K<A
如果把所有扑克牌排成以下次序:
♣2,…,♣A,♦2,…,♦A,♥2,…,♥A,♠2,…,♠A
这就是多排序码排序。排序后形成的有序序列叫做字典有序序列。
一般情况下,假定有一个n个元素的序列
{V0,V1,...,Vn−1}
,且每个元素
Vi
中含有
d
个排序码
实现多排序码排序有两种常用的方法:一种方法是最高位优先(Most Significant Digit first,MSD),一种方法是最低位优先(Least Significant Digit first,LSD)。
MSD基数排序
基本思想
首先根据最高位关键码 K1 得到若干对象组,对象组中的每个对象都有对象都有相同的关键码K1;再分别对每组中的对象根据关键码 K2 进行排序,按K2值的不同,再分成若干个更小的子组,子组中的对象具有相同的 K1 和 K2 值;依次重复,直到对关键码 Kd 完成排序为止。最后,把所有子组中的对象依次连接起来,就得到一个有序的对象序列。
代码
private int radix = 10;//基数,默认十进制
private void msdRadixSort(int[] a, int left, int right, int d) {
int[] auxArray = new int[a.length];// 辅助数组,存放按桶分配的结果,根据count[]预先算定各桶元素的使用位置
int[] count = new int[right-left+1];// 辅助数组,记录当处理第i位时各个元素的第i位取值为k的有多少个。
int i, j;
if (d > 0) {//位数尚未处理完
//初始化count数组
for (i = 0; i < radix; i++)
count[i] = 0;
//统计各桶元素的个数
for (i = left; i <= right; i++)
count[getDigit(a[i], d)]++;
//计算各桶元素的存放位置
for (i = 1; i < radix; i++)
count[i] = count[i] + count[i - 1];
//将待排序列中的元素按位值分配到各个桶中,存于辅助数组auxArray中
for (i = left; i <= right; i++) {
j = getDigit(a[i], d); //取元素a[i]第d位的值
auxArray[count[j] - 1] = a[i]; //按预先计算位置存放
count[j]--; //计数器减1
}
//从辅助数组顺序写入原数组
for (i = left, j = 0; i <= right; i++, j++)
a[i] = auxArray[j];
//按桶递归对d-1位处理
for (j = 0; j < radix - 1; j++) {
int p1 = count[j]; //取桶开始端
int p2 = count[j + 1] - 1; //取桶结束端
if (p1 < p2 && d > 1)
msdRadixSort(a, p1, p2, d - 1);//对桶内元素进行基数排序
}
}
}
LSD基数排序
基本思想
首先依据最低位排序码 Kd 对所有元素进行一趟排序,然后依据次低位排序码 Kd−1 对上一趟排序的结果再排序,依次重复,直到依据排序码 K1 最后一趟排序完成,就可以得到一个有序的序列。使用这种排序方法对每个排序码进行排序时,不需要再分组,而是整个元素组都参加排序。
代码
private void lsdRadixSort(int[] a, int left, int right, int d) {
int[] auxArray = new int[a.length];// 辅助数组,存放按桶分配的结果,根据count[]预先算定各桶元素的使用位置
int[] count = new int[right-left+1];// 辅助数组,记录当处理第i位时各个元素的第i位取值为k的有多少个。
int i, j, k;
for (k = 1; k <= d; k++) {
for (i = 0; i < radix; i++)
count[i] = 0;
for (i = left; i <= right; i++)
count[getDigit(a[i], k)]++;
for (i = 1; i < radix; i++)
count[i] = count[i] + count[i - 1];
for (i = left; i <= right; i++) {
j = getDigit(a[i], k);
auxArray[count[j] - 1] = a[i];
count[j]--;
}
// 从辅助数组顺序写入原数组
for (i = left, j = 0; i <= right; i++, j++)
a[i] = auxArray[j];
}
}