详解基数排序算法原理与使用方法

基数排序算法详解

概述

基数排序是一种非比较排序算法。此算法的思想是将整数按位数切割成不同的数字,然后按每个位数分别比较。在排序过程中,需要使用稳定的排序算法,也就是说在位数排序中相同的数字,后面的应该比前面的先出现。

算法步骤

  1. 获取待排序的数组arr,确定最大数的位数max_digit;
  2. 对max_digit做循环,在每轮循环中,按照该位数大小对待排序数组arr进行基数排序(桶排序);
  3. 将每轮基数排序后的数组重新组合为一个新数组。

基数排序示例

示例一

假设待排序数组如下:

arr = [53, 3, 542, 748, 14, 214, 154, 63, 616]
  1. 获取最大位数

首先,需要获取最大数的位数,最大数为748,位数为3。因此,需要进行三轮基数排序。

  1. 第一轮基数排序

以个位数为比较规则,将待排序数组放入十个桶中,是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]
  1. 第二轮基数排序

以十位数为比较规则,将待排序数组放入十个桶中,类似如下操作:

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]
  1. 第三轮基数排序

以百位数为比较规则,将待排序数组放入十个桶中,类似如下操作:

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]
  1. 合并每轮排序结果

得到最终的排序结果:

arr = [3, 14, 53, 63, 154, 214, 542, 616, 748]

示例二

假设待排序数组如下:

arr = [170, 45, 75, 90, 802, 24, 2, 66]
  1. 获取最大位数

首先,需要获取最大数的位数,最大数为802,位数为3。因此,需要进行三轮基数排序。

  1. 第一轮基数排序

以个位数为比较规则,将待排序数组放入十个桶中,类似如下操作:

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]
  1. 第二轮基数排序

以十位数为比较规则,将待排序数组放入十个桶中,类似如下操作:

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]
  1. 第三轮基数排序

以百位数为比较规则,将待排序数组放入十个桶中,类似如下操作:

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]
  1. 合并每轮排序结果

得到最终的排序结果:

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为数组长度,一般来说是比较稳定的。