"""
This is a pure Python implementation of the radix sort algorithm
Source: https://en.wikipedia.org/wiki/Radix_sort
"""
from __future__ import annotations
RADIX = 10
def radix_sort(list_of_ints: list[int]) -> list[int]:
"""
Examples:
>>> radix_sort([0, 5, 3, 2, 2])
[0, 2, 2, 3, 5]
>>> radix_sort(list(range(15))) == sorted(range(15))
True
>>> radix_sort(list(range(14,-1,-1))) == sorted(range(15))
True
>>> radix_sort([1,100,10,1000]) == sorted([1,100,10,1000])
True
"""
placement = 1
max_digit = max(list_of_ints)
while placement <= max_digit:
# declare and initialize empty buckets
buckets: list[list] = [[] for _ in range(RADIX)]
# split list_of_ints between the buckets
for i in list_of_ints:
tmp = int((i / placement) % RADIX)
buckets[tmp].append(i)
# put each buckets' contents into list_of_ints
a = 0
for b in range(RADIX):
for i in buckets[b]:
list_of_ints[a] = i
a += 1
# move to next
placement *= RADIX
return list_of_ints
if __name__ == "__main__":
import doctest
doctest.testmod()
基于比较的排序算法(归并排序、堆排序、快速排序等)的下界为 Ω(nlogn)
,即它们无法比 nlogn
更好。
计数排序是一种线性时间排序算法,当元素范围在 1 到 k 之间时,可以在 O(n+k)
时间内完成排序。
如果元素的范围在 1 到 n2 之间呢?我们不能使用计数排序,因为计数排序将需要 O(n2)
的时间,这比基于比较的排序算法更差。我们能否在线性时间内对这样的数组进行排序?
基数排序就是答案。基数排序的思想是从最低有效位到最高有效位逐位进行排序。基数排序使用计数排序作为子程序来进行排序。
对每个数字 i 执行以下操作,其中 i 从最低有效位到最高有效位变化。使用计数排序(或任何稳定的排序)根据第 i 位对输入数组进行排序。
示例
原始的、未排序的列表:170, 45, 75, 90, 802, 24, 2, 66
按最低有效位(个位)排序得到
[*注意,我们将 802 保留在 2 之前,因为 802 在原始列表中出现在 2 之前,类似地,对于 170 和 90 以及 45 和 75 也是如此。]
按下一位(十位)排序得到
[*注意,802 再次出现在 2 之前,因为 802 在上一列表中出现在 2 之前。]
802, 2, 24, 45, 66, 170, 75, 90
按最高有效位(百位)排序得到:2, 24, 45, 66, 75, 90, 170, 802
假设输入整数中有 d 位数字。基数排序需要 O(d*(n+b))
的时间,其中 b 是表示数字的基数,例如,对于十进制系统,b 为 10。d 的值是多少?如果 k
是最大可能值,则 d 将为 O(logb(k))
。因此,总体时间复杂度为 O((n+b) * logb(k))
。对于较大的 k,这看起来比基于比较的排序算法的时间复杂度要大。让我们首先限制 k。假设 k <= nc,其中 c 是一个常数。在这种情况下,复杂度变为 O(n logb(n))
。但它仍然没有击败基于比较的排序算法。
如果每个数字都有 log2n
位,那么在广泛的输入数字范围内,基数排序的运行时间似乎优于快速排序。基数排序中隐藏在渐近表示法中的常数因子较高,而快速排序更有效地利用硬件缓存。此外,基数排序使用计数排序作为子程序,而计数排序需要额外的空间来对数字进行排序。