1、概述
基数排序属于分配式排序,又称 桶子法,他是透过键值的部分咨询,将要排序的元素分配至某些桶中,借以达到排序的作用。
基数排序是属于稳定性的排序
2、算法原理
基本原理:利用桶来实现,然后按照基数入桶,基数的取值是从数字的低位到高位以此取值
步骤:
1)以无序序列数值的个数为基数,将无序序列的值进入到基数对应的桶中
2)个位数为基数入桶完毕后,在安装编号从小到大将桶中的数据以此取出,再存入之前的数组中
3)在2中生成的数组的基础上再以式位数为基准入桶,入桶完毕后,再次按照桶的编号顺序将数值取出
注:排序的数值越大,入桶出桶的次数就越多,所以随着位数的增大,效率会降低
3、举例
以[62, 88, 58, 47, 62, 35, 73, 51, 99, 37, 93]排序为例
1)取个数为基数,以62为例,取个数为基数,62在本轮进入编号为2的桶中
2)1)排序完,在安装编号从大到小将桶中的数据取出,存入之前的数组
3)取十位数为基数入桶,排序完按顺序取出,数组中最高位是十位数,即十位数出桶入桶后,数组已经排序完成,如果还有高位,需要继续取基数排序,直到最高位排序完成
4、算法实现
//1、创建n个空桶
/*
返回结果的类型是Array<Array<Int>>,是一个二维数组。
内层数组就是一个桶,负责存放与该桶编号相等的基数对应的数值
*/
private func createBucket(_ n : Int)->Array<Array<Int>>{
var bucket : Array<Array<Int>> = []
for _ in 0..<n {
bucket.append([])
}
return bucket
}
//2、计算无序序列中最大的那个数
/*
取基数入桶出桶的次数以此最大数值的位数为准
*/
private func listMaxItem(_ list : Array<Int>)->Int{
var maxNumber = list[0]
for item in list {
if maxNumber < item {
maxNumber = item
}
}
return maxNumber
}
//3、获取数字的长度----即取基数的次数
private func numberLength(_ num : Int)->Int{
return "\(num)".count
}
//4、获取数值中特定位数的值
/*
通过取余以及求模的方式获取 / 采用将数字转换成字符串,然后将字符串转换成字符串数组
*/
private class func fetchBaseNumber(_ num : Int, _ digit : Int)->Int{
if digit > 0 && digit<=SortSummary.numberLength(num) {
var numArr : Array<Int> = []
for char in "\(num)" {
numArr.append(Int("\(char)")!)
}
return numArr[numArr.count-digit]
}
return 0
}
//5、排序
func radixSort(_ list : inout Array<Int>){
var bucket = createBucket(list.count)
var maxNum = listMaxItem(list)
let maxLength = numberLength(maxNum)
for digit in 1...maxLength {
//入桶
for item in list {
let baseNum = fetchBaseNumber(item, digit)
//根据基数进入相应的桶中
bucket[baseNum].append(item)
}
//出桶
var index = 0
for i in 0..<bucket.count{
while !bucket[i].isEmpty {
list[index] = bucket[i].remove(at: 0)
index += 1
}
}
}
}
调用:
var array9 = [62, 88, 58, 47, 62, 35, 73, 51, 99, 37, 93]
radixSort(&array9)
运行结果:
[35, 37, 47, 51, 58, 62, 62, 73, 88, 93, 99]
5、时间复杂度
基数排序的时间复杂度为O(d(n+radix)),其中,一趟分配时间复杂度为O(n),一趟收集时间复杂度为O(radix),共进行d趟分配和收集
注:排序的具体实现代码在 SortSummary.swift 文件里 调用是在 ViewController.swift