基数排序算法详解
概述
基数排序是一种非比较排序算法。此算法的思想是将整数按位数切割成不同的数字,然后按每个位数分别比较。在排序过程中,需要使用稳定的排序算法,也就是说在位数排序中相同的数字,后面的应该比前面的先出现。
算法步骤
- 获取待排序的数组arr,确定最大数的位数max_digit;
- 对max_digit做循环,在每轮循环中,按照该位数大小对待排序数组arr进行基数排序(桶排序);
- 将每轮基数排序后的数组重新组合为一个新数组。
基数排序示例
示例一
假设待排序数组如下:
arr = [53, 3, 542, 748, 14, 214, 154, 63, 616]
- 获取最大位数
首先,需要获取最大数的位数,最大数为748,位数为3。因此,需要进行三轮基数排序。
- 第一轮基数排序
以个位数为比较规则,将待排序数组放入十个桶中,是ore类似如下操作:
temp = [[] for _ in range(10)]
for i in arr:
temp[i % 10].append(i)
复制每个桶,将每个桶内的元素按顺序放回原数组,是这么做的:
arr = []
for i in temp:
arr += i
得到第一轮基数排序后的数组:
arr = [53, 3, 63, 542, 214, 14, 154, 748, 616]
- 第二轮基数排序
以十位数为比较规则,将待排序数组放入十个桶中,类似如下操作:
temp = [[] for _ in range(10)]
for i in arr:
temp[i // 10 % 10].append(i)
复制每个桶,将每个桶内的元素按顺序放回原数组,是这么做的:
arr = []
for i in temp:
arr += i
得到第二轮基数排序后的数组:
arr = [3, 14, 53, 63, 154, 214, 542, 616, 748]
- 第三轮基数排序
以百位数为比较规则,将待排序数组放入十个桶中,类似如下操作:
temp = [[] for _ in range(10)]
for i in arr:
temp[i // 100].append(i)
复制每个桶,将每个桶内的元素按顺序放回原数组,是这么做的:
arr = []
for i in temp:
arr += i
得到第三轮基数排序后的数组:
arr = [3, 14, 53, 63, 154, 214, 542, 616, 748]
- 合并每轮排序结果
得到最终的排序结果:
arr = [3, 14, 53, 63, 154, 214, 542, 616, 748]
示例二
假设待排序数组如下:
arr = [170, 45, 75, 90, 802, 24, 2, 66]
- 获取最大位数
首先,需要获取最大数的位数,最大数为802,位数为3。因此,需要进行三轮基数排序。
- 第一轮基数排序
以个位数为比较规则,将待排序数组放入十个桶中,类似如下操作:
temp = [[] for _ in range(10)]
for i in arr:
temp[i % 10].append(i)
复制每个桶,将每个桶内的元素按顺序放回原数组,是这么做的:
arr = []
for i in temp:
arr += i
得到第一轮基数排序后的数组:
arr = [170, 90, 802, 2, 24, 45, 75, 66]
- 第二轮基数排序
以十位数为比较规则,将待排序数组放入十个桶中,类似如下操作:
temp = [[] for _ in range(10)]
for i in arr:
temp[i // 10 % 10].append(i)
复制每个桶,将每个桶内的元素按顺序放回原数组,是这么做的:
arr = []
for i in temp:
arr += i
得到第二轮基数排序后的数组:
arr = [802, 2, 24, 45, 66, 170, 75, 90]
- 第三轮基数排序
以百位数为比较规则,将待排序数组放入十个桶中,类似如下操作:
temp = [[] for _ in range(10)]
for i in arr:
temp[i // 100].append(i)
复制每个桶,将每个桶内的元素按顺序放回原数组,是这么做的:
arr = []
for i in temp:
arr += i
得到第三轮基数排序后的数组:
arr = [2, 24, 45, 66, 75, 90, 170, 802]
- 合并每轮排序结果
得到最终的排序结果:
arr = [2, 24, 45, 66, 75, 90, 170, 802]
使用方法
在实际代码实现时,我们可以将基数排序分为两种不同的实现方式:LSD(Least Significant Digit)和MSD(Most Significant Digit)。
LSD是从低位开始排序,而MSD是从高位开始排序。在 Python 中,我们可以使用如下代码实现 LSD 基数排序:
def radix_sort_lsd(arr):
if not arr:
return []
max_digit = len(str(max(arr)))
for i in range(max_digit):
temp = [[] for _ in range(10)]
for j in arr:
temp[j // (10 ** i) % 10].append(j)
arr = []
for j in temp:
arr.extend(j)
return arr
而 MSD 基数排序则可以如下实现:
def radix_sort_msd(arr):
if not arr:
return []
max_digit = len(str(max(arr)))
radix_sort_msd_helper(arr, 0, len(arr)-1, max_digit-1)
return arr
def radix_sort_msd_helper(arr, left, right, digit):
if digit < 0 or left >= right:
return
temp = [[] for _ in range(10)]
for i in range(left, right+1):
temp[arr[i] // (10 ** digit) % 10].append(arr[i])
temp_left = left
for i in range(10):
temp_right = temp_left + len(temp[i]) - 1
arr[temp_left:temp_right+1] = temp[i]
radix_sort_msd_helper(arr, temp_left, temp_right, digit-1)
temp_left = temp_right + 1
以上两种实现方式,LSD基数排序要比MSD基数排序简单,而 MSD 基数排序虽然比 LSD 的实现略微复杂了一点,但是在实现上可以做到更加高效。具体选择何种实现方式,要根据实际情况及自己的习惯进行选择。
总结
基数排序算法是一种非常实用的排序算法,适用于处理大量整数,且范围较小的数据排序。它的时间复杂度是O(kn),其中k为最大值的十进制位数,n为数组长度,一般来说是比较稳定的。