[Swift]基数排序 | Radix sort

★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
➤微信公众号:山青咏芝(shanqingyongzhi)
➤博客园地址:山青咏芝(https://www.cnblogs.com/strengthen/
➤GitHub地址:https://github.com/strengthen/LeetCode
➤原文地址:https://www.cnblogs.com/strengthen/p/11075286.html 
➤如果链接不是山青咏芝的博客园地址,则可能是爬取作者的文章。
➤原文已修改更新!强烈建议点击原文地址阅读!支持作者!支持原创!
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

1、定义

基数排序是一种非比较型整数排序算法,又称“桶子法”(bucket sort)或bin sort,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。

基数排序的方式可以采用:

 (1)、LSD(Least significant digital):排序方式由数值的最右边(低位)开始。

 (2)、MSD(Most significant digital):由数值的最左边(高位)开始。

2、基数排序、计数排序、桶排序中对桶的使用方法上的差异:

基数排序:根据键值的每位数字来分配桶。

计数排序:每个桶只存储单一键值。

桶排序:每个桶存储一定范围的数值。

3、算法原理:基数排序是通过“分配”和“收集”过程来实现排序。

(1)、分配,先从个位开始,根据位值(0-9)分别放到0~9号桶中(比如64,个位为4,则放入4号桶中)

(2)、收集,再将放置在0~9号桶中的数据按顺序放到数组中

重复(1)(2)过程,从个位到最高位(比如32位无符号整形最大数3494967296,最高位10位)。

4、算法分析

最坏时间复杂度:其中w是存储每个密钥所需的位数。

最坏空间复杂度:

5、LSD基数排序

最低位优先法首先依据最低位关键码Kd对所有对象进行一趟排序,再依据次低位关键码Kd-1对上一趟排序的结果再排序,依次重复,直到依据关键码K1最后一趟排序完成,就可以得到一个有序的序列。使用这种排序方法对每一个关键码进行排序时,不需要再分组,而是整个对象组。因为分配和收集阶段,数字符合先入先出的关系。因此可以用10个队列来保存 0-9 上分配的数字,在收集阶段,按先入先出的顺序取出每个桶中的数字,依次放到原数组中。

LSD代码1:

 1 import Foundation
 2 //MARK:基数排序LSD
 3 func radixSort(_ unsortedArray: [Int]) -> [Int]{
 4     var unsortedArray = unsortedArray
 5     
 6     var tempArray = [Int]()
 7     var maxValue = 0
 8     var maxDigit = 0
 9     var level = 0
10     
11     repeat {
12         var buckets = [[Int]]()
13         for _ in 0..<10 {
14             buckets.append([Int]())
15         }
16         
17         for i in 0..<unsortedArray.count {
18             let elementValue = unsortedArray[i]
19             let num = pow(10.0, Double(level))
20             let divident = level < 1 ? 1 : NSDecimalNumber(decimal:Decimal(num)).intValue
21             let mod = elementValue / divident % 10
22             buckets[mod].append(elementValue)
23             
24             if maxDigit == 0 {
25                 if elementValue > maxValue {
26                     maxValue = elementValue
27                 }
28             }
29         }
30         
31         tempArray.removeAll()
32         for element in buckets {
33             tempArray.append(contentsOf: element)
34         }
35         
36         if maxDigit == 0 {
37             while maxValue > 0 {
38                 maxValue = maxValue / 10
39                 maxDigit += 1
40             }
41         }
42         
43         unsortedArray = tempArray
44         level += 1
45         
46     } while (level < maxDigit)
47     
48     return tempArray
49 }

测试:

1 var arr:[Int] = [1,9,2,8,3,7,4,6,5,10,11,12]
2 print(radixSort(arr))
3 //Print [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

LSD代码2:

 1 import Foundation
 2 //MARK:基数排序LSD
 3 func radixSort(_ arr:inout [Int]) {
 4     if arr.count == 0 {
 5         return
 6     }
 7     var list:[[Int]] = [[Int]](repeating:[Int](),count:10)
 8     
 9     let maxDigit:Int = maxlength(arr: arr)
10     var tempArr:[Int] = arr
11     for i in 0..<maxDigit {
12         for j in 0..<arr.count {
13             let index:Int = highDigit(num: tempArr[j], index: i)
14             list[index].append(tempArr[j])
15         }
16         saveBucketData(bucketlist: &list, arr: &tempArr)
17     }
18     arr = tempArr
19 }
20 21 // 桶的数据插入数组
22 private func saveBucketData(bucketlist:inout [[Int]],arr:inout [Int]) {
23     var index:Int = 0
24     for i in 0..<bucketlist.count {
25         var bucket:[Int] = bucketlist[i]
26         if bucket.count > 0 {
27             for j in 0..<bucket.count {
28                 arr[index] = bucket[j]
29                 index += 1
30             }
31         }
32         bucketlist[i].removeAll() // 注意清空桶数据
33     }
34 }
35 36 private func highDigit(num:Int,index:Int)->Int {
37     let base:Double = pow(10, Double(index))
38     let high:Int = (num / Int(base)) % 10
39     return high
40 }
41 42 // 最大数字的位数
43 private func maxlength(arr:[Int])->Int {
44     var max:Int = 0
45     for i in 0..<arr.count {
46         let count:Int = positionOfNum(number: arr[i])
47         if count > max {
48             max = count
49         }
50     }
51     return max
52 }
53 54 // 统计数字的位数
55 private func positionOfNum(number:Int)->Int {
56     var count:Int = 0
57     var num:Int = number
58     while num%10 > 0  {
59         count += 1
60         num = num / 10
61     }
62     return count
63 }

测试:

1 var arr:[Int] = [1,9,2,8,3,7,4,6,5,10,11,12]
2 print(radixSort(arr))
3 //Print [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

LSD代码3:

 1 import Foundation
 2 //MARK:基数排序LSD
 3 func radixSort(_ arr:inout [Int]){
 4     let n = arr.count
 5     let maxNum:Int = arr.max()!
 6     let d:Double = pow(10.0, Double(String(maxNum).count))
 7     var k:Int = 1
 8     //
 9     var t:[[Int]] = [[Int]](repeating:[Int](repeating:0,count:n), count: 10)
10     //记录每个桶中存入数的个数
11     var num:[Int] = [Int](repeating: 0, count: n)
12     while(Double(k) < d)
13     {
14         for a in arr
15         {
16             let m:Int = (a / k) % 10
17             t[m][num[m]] = a
18             num[m] += 1
19         }
20         var c:Int = 0
21         for i in 0..<n
22         {
23             if num[i] != 0
24             {
25                 for j in 0..<num[i]
26                 {
27                     arr[c] = t[i][j]
28                     c += 1
29                 }
30             }
31             num[i] = 0
32         }
33         k = k * 10
34     }
35 }

测试:

1 var arr:[Int] = [1,9,2,8,3,7,4,6,5,10,11,12]
2 print(radixSort(arr))
3 //Print [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

6、MSD基数排序

最高位优先法通常是一个递归的过程:

(1)、先根据最高位关键码K1排序,得到若干对象组,对象组中每个对象都有相同关键码K1。

(2)、再分别对每组中对象根据关键码K2进行排序,按K2值的不同,再分成若干个更小的子组,每个子组中的对象具有相同的K1和K2值。

(3)、依此重复,直到对关键码Kd完成排序为止。

(4)、 最后,把所有子组中的对象依次连接起来,就得到一个有序的对象序列。

 1 import Foundation
 2 //MARK:基数排序MSD
 3 //MSD调用时指定最高位数d
 4 func radixSort(_ arr:inout [Int],_ d:Int){
 5     let len:Int = arr.count
 6     //分为0~9的序列空间,用队列保存每个桶分配的数据
 7     var radixArray:[[Int]] = [[Int]](repeating: [Int](), count: 10)
 8     //位数大于0,且数组长度大于1
 9     if d >= 1 && len > 1
10     {
11         //分配过程
12         for i in 0..<len
13         {
14             let num:Int = GetNumInPos(arr[i], d)
15             radixArray[num].append(arr[i])
16         }
17         var i:Int = 0
18         var j:Int = 0
19          //收集
20         while(i < 10)
21         {
22             //递归,对每个子桶从次高位开始分配
23             radixSort(&radixArray[i], d - 1)
24             
25             while(!radixArray[i].isEmpty)
26             {
27                 //取队列首部数据依次插入原数组
28                 arr[j] = radixArray[i].first!
29                 j += 1
30                 radixArray[i].removeFirst()
31             }
32             i += 1
33         }
34     }
35 }
36 37 func GetNumInPos(_ num:Int, _ pos:Int)-> Int
38 {
39     var temp:Int =  1
40     for _ in 0..<(pos - 1)
41     {
42         temp *= 10
43     }
44     return (num / temp) % 10
45 }

测试:

1 var arr:[Int] = [1,9,2,8,3,7,4,6,5,10,11,12]
2 radixSort(&arr,arr.count)
3 print(arr)
4 //Print [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
 
原文地址:https://www.cnblogs.com/strengthen/p/11075286.html