The Algorithms logo
算法
关于我们捐赠

基数排序

S
m
A
R
A
P
以及 1 位其他贡献者
"""
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 位,那么在广泛的输入数字范围内,基数排序的运行时间似乎优于快速排序。基数排序中隐藏在渐近表示法中的常数因子较高,而快速排序更有效地利用硬件缓存。此外,基数排序使用计数排序作为子程序,而计数排序需要额外的空间来对数字进行排序。

视频解释

视频参考:https://youtu.be/nu4gDuFabIM