6. 基数排序
也叫桶排序或箱排序
6.1.1 算法分析和思路
-
基本思想:
分配+收集- 分配:设置若干个箱子,将关键字为k的记录放入第k个箱子;
- 收集:按序号将非空的连接。
-
数字是有范围的,均由0-9这十个数字组成,则只需设置十个箱子,相继按个、十、百…进行排序。
注:
算法思路及详细过程可参考后续的示例和代码及代码流程图!
6.1.2 算法示例
6.1.3 算法代码
//基数排序算法
void RadixSort(SqList &L){
int len = L.length;
int maxBitNum = MaxBitNum(L);//获取数据的最大位数
int *count = new int[10];//计数器,关键字取值范围10个值:0~9
ReadType *tempNums = new ReadType[len];//新建辅助数组tempNums
int radix = 1;//基数初始为1,即表示个位
int i, j;
int k;
//进行maxBitNum次排序
for(i = 1; i <= maxBitNum; i++){
//每次分配前清空计数器
for(j = 0; j < 10; j++){
count[j] = 0;
}
//统计每个桶中的记录数
for(j = 1; j <= len; j++){//有哨兵位,索引从1开始
k = (L.nums[j].key / radix) % 10;
count[k]++;
}
//将tempNum中的位置依次分给每一个桶
for(j = 1; j < 10; j++){
count[j] = count[j-1] + count[j];
}
//将所有桶中记录依次收集到tempNum中
for(j = len; j >= 1; j--){//有哨兵位,索引从1开始
k = (L.nums[j].key / radix) % 10;
tempNums[count[k] - 1] = L.nums[j];
count[k]--;
}
//将临时数组中的值复制到L.nums[]中
for(j = 0; j < len; j++){
L.nums[j+1] = tempNums[j];
}
radix *= 10;
}
}
//辅助函数,求关键字个数,即求数据的最大位数
//先求出最大数,再求出其位数
int MaxBitNum(SqList &L){
KeyType maxData = L.nums[1].key;
//先求出最大数
for(int i = 2; i<= L.length; i++){
if(L.nums[i].key > maxData){
maxData = L.nums[i].key;
}
}
//再求出最大位数,即最大数的位数
int maxBitNum = 1;
while(maxData >= 10){
maxData /= 10;
maxBitNum++;
}
return maxBitNum;
}
- 代码流程图:
6.1.4 算法性能分析
- 时间复杂度:
O
(
k
∗
(
n
+
m
)
)
O(k*(n+m))
O(k∗(n+m))
- k:关键字个数,决定了需要分配多少趟;
- m:关键字取值范围为m个值。桶的个数,有多少个桶,收集时就要收集多少次;
- n:分配时,每趟要往桶里扔多少个元素。
- 每一趟都需要扔n个,收m次,总共需要k趟
- 空间复杂度: O ( n + m ) O(n+m) O(n+m)
- 是一种稳定的排序方法