基数排序原理与Python实现详解

基数排序全面详解:原理、Python实现与动图演示

1. 基数排序基本概念

基数排序(Radix Sort)是一种非比较型的整数排序算法,其核心思想是按照键值的每位数字来分配和收集元素。与基于比较的排序算法(如快速排序、归并排序)不同,基数排序通过多轮的"分配"和"收集"操作来实现排序,特别适合处理整数或固定长度字符串的排序问题。

1.1 算法特点

特性 说明
时间复杂度 O(d×(n+k)),其中d是最大数字的位数,k是基数
空间复杂度 O(n+k)
稳定性 稳定排序算法
适用场景 整数、固定长度字符串排序

2. 基数排序工作原理

2.1 基本思想

基数排序采用"最低位优先"(LSD, Least Significant Digit first)或"最高位优先"(MSD, Most Significant Digit first)的策略。LSD从最低位开始排序,MSD从最高位开始排序。

算法步骤:

  1. 找到数组中最大数,确定最大位数
  2. 从最低位开始,按照每个位数进行排序
  3. 使用稳定的排序算法对每个位数进行排序(通常用计数排序)
  4. 重复步骤2-3,直到最高位排序完成

2.2 动图演示原理

虽然无法直接嵌入动图,但可以通过文字描述动图演示过程:

复制代码
初始数组: [170, 45, 75, 90, 2, 802, 24, 66]

第1轮(个位排序):
- 按个位数分配到桶中:
  桶0: 170, 90
  桶2: 2, 802
  桶4: 24
  桶5: 45, 75
  桶6: 66
- 收集: [170, 90, 2, 802, 24, 45, 75, 66]

第2轮(十位排序):
- 按十位数分配到桶中:
  桶0: 2, 802
  桶2: 24
  桶4: 45
  桶6: 66
  桶7: 170, 75
  桶9: 90
- 收集: [2, 802, 24, 45, 66, 170, 75, 90]

第3轮(百位排序):
- 按百位数分配到桶中:
  桶0: 2, 24, 45, 66, 75, 90
  桶1: 170
  桶8: 802
- 收集: [2, 24, 45, 66, 75, 90, 170, 802]

最终得到有序数组。

3. Python实现基数排序

3.1 基础版本实现

python 复制代码
def radix_sort(arr):
    """
    基数排序算法实现(LSD方式)
    
    参数:
    arr: 待排序的整数列表
    
    返回:
    排序后的整数列表
    """
    # 找到最大数,确定最大位数
    if not arr:
        return arr
    
    max_num = max(arr)
    exp = 1  # 当前处理的位数(1表示个位,10表示十位,以此类推)
    
    # 当max_num // exp > 0时,继续排序
    while max_num // exp > 0:
        # 使用计数排序对当前位数进行排序
        counting_sort_for_radix(arr, exp)
        exp *= 10
    
    return arr

def counting_sort_for_radix(arr, exp):
    """
    用于基数排序的计数排序子函数
    
    参数:
    arr: 待排序数组
    exp: 当前处理的位数
    """
    n = len(arr)
    output = [0] * n  # 输出数组
    count = [0] * 10  # 计数数组(0-9)
    
    # 统计每个数字出现的次数
    for i in range(n):
        index = (arr[i] // exp) % 10
        count[index] += 1
    
    # 计算累积计数
    for i in range(1, 10):
        count[i] += count[i - 1]
    
    # 构建输出数组(从后往前保持稳定性)
    i = n - 1
    while i >= 0:
        index = (arr[i] // exp) % 10
        output[count[index] - 1] = arr[i]
        count[index] -= 1
        i -= 1
    
    # 将排序结果复制回原数组
    for i in range(n):
        arr[i] = output[i]

# 测试示例
if __name__ == "__main__":
    test_arr = [170, 45, 75, 90, 2, 802, 24, 66]
    print("原始数组:", test_arr)
    sorted_arr = radix_sort(test_arr)
    print("排序后数组:", sorted_arr)

3.2 完整功能版本

python 复制代码
def advanced_radix_sort(arr, radix=10):
    """
    增强版基数排序,支持自定义基数
    
    参数:
    arr: 待排序数组
    radix: 基数(默认10进制)
    
    返回:
    排序后的数组
    """
    if len(arr) <= 1:
        return arr
    
    # 计算最大数的位数
    max_val = max(arr)
    max_digit = 0
    while max_val > 0:
        max_digit += 1
        max_val //= radix
    
    # 逐位排序
    for digit in range(max_digit):
        # 创建桶
        buckets = [[] for _ in range(radix)]
        
        # 分配元素到桶中
        for num in arr:
            # 获取当前位的数字
            current_digit = (num // (radix ** digit)) % radix
            buckets[current_digit].append(num)
        
        # 收集桶中的元素
        arr = []
        for bucket in buckets:
            arr.extend(bucket)
    
    return arr

# 测试不同场景
def test_radix_sort():
    """测试基数排序的各种场景"""
    
    # 测试1:普通整数排序
    test1 = [329, 457, 657, 839, 436, 720, 355]
    print("测试1 - 普通整数:")
    print("排序前:", test1)
    print("排序后:", advanced_radix_sort(test1))
    
    # 测试2:包含负数的排序(需要特殊处理)
    test2 = [123, -45, 67, -89, 0, 456, -123]
    print("
测试2 - 包含负数:")
    print("排序前:", test2)
    
    # 处理负数的方法:分离正负数分别排序
    positive = [x for x in test2 if x >= 0]
    negative = [-x for x in test2 if x < 0]
    
    positive_sorted = advanced_radix_sort(positive)
    negative_sorted = advanced_radix_sort(negative)
    
    final_sorted = [-x for x in reversed(negative_sorted)] + positive_sorted
    print("排序后:", final_sorted)
    
    # 测试3:大量数据排序
    import random
    test3 = [random.randint(0, 10000) for _ in range(20)]
    print("
测试3 - 大量数据:")
    print("排序前:", test3[:10], "...")  # 只显示前10个
    sorted_test3 = advanced_radix_sort(test3)
    print("排序后:", sorted_test3[:10], "...")

if __name__ == "__main__":
    test_radix_sort()

4. 算法复杂度分析

4.1 时间复杂度

基数排序的时间复杂度为 O(d×(n+k)),其中:

  • d:最大数字的位数
  • n:数组元素个数
  • k:基数(通常为10)

当d为常数且k=O(n)时,时间复杂度可视为O(n)。

4.2 空间复杂度

空间复杂度为 O(n+k),主要用于:

  • 输出数组:O(n)
  • 计数数组:O(k)

4.3 性能对比

排序算法 平均时间复杂度 最好情况 最坏情况 空间复杂度 稳定性
基数排序 O(d×(n+k)) O(d×(n+k)) O(d×(n+k)) O(n+k) 稳定
快速排序 O(n log n) O(n log n) O(n²) O(log n) 不稳定
归并排序 O(n log n) O(n log n) O(n log n) O(n) 稳定
堆排序 O(n log n) O(n log n) O(n log n) O(1) 不稳定

5. 应用场景与优缺点

5.1 适用场景

  1. 整数排序:特别适合处理大量整数的排序问题
  2. 固定长度字符串排序:如电话号码、身份证号等
  3. 多关键字排序:当需要按多个条件排序时
  4. 数据范围较小但数量大的情况

5.2 优点

  • 线性时间复杂度:在特定条件下可以达到线性时间复杂度
  • 稳定性:保持相等元素的相对顺序
  • 可预测性:时间复杂度稳定,不受输入数据分布影响

5.3 缺点

  • 适用范围有限:主要适用于整数和固定长度字符串
  • 空间开销:需要额外的存储空间
  • 基数依赖:性能受选择的基数影响

6. 实际应用案例

python 复制代码
class StudentSorter:
    """
    使用基数排序对学生信息进行多关键字排序
    """
    
    @staticmethod
    def sort_students_by_score(students):
        """
        按分数排序学生(假设分数为0-1000的整数)
        """
        scores = [student['score'] for student in students]
        sorted_scores = radix_sort(scores)
        
        # 构建分数到学生的映射
        score_to_students = {}
        for student in students:
            score = student['score']
            if score not in score_to_students:
                score_to_students[score] = []
            score_to_students[score].append(student)
        
        # 按排序后的分数顺序重组学生列表
        sorted_students = []
        for score in sorted_scores:
            if score in score_to_students and score_to_students[score]:
                sorted_students.append(score_to_students[score].pop())
        
        return sorted_students
    
    @staticmethod
    def sort_by_multiple_criteria(students):
        """
        多关键字排序:先按班级,再按学号
        """
        # 提取班级和学号信息
        class_numbers = [student['class'] for student in students]
        student_ids = [student['id'] for student in students]
        
        # 先按学号排序(次要关键字)
        temp_sorted = advanced_radix_sort(list(range(len(students))), 
                                        key=lambda x: student_ids[x])
        
        # 再按班级排序(主要关键字)
        final_sorted = advanced_radix_sort(temp_sorted, 
                                         key=lambda x: class_numbers[x])
        
        return [students[i] for i in final_sorted]

# 使用示例
students = [
    {'name': '张三', 'score': 856, 'class': 3, 'id': 1003},
    {'name': '李四', 'score': 723, 'class': 1, 'id': 1001},
    {'name': '王五', 'score': 856, 'class': 2, 'id': 1002},
]

print("按分数排序:")
sorted_by_score = StudentSorter.sort_students_by_score(students)
for student in sorted_by_score:
    print(f"{student['name']}: {student['score']}分")

基数排序作为一种高效的线性时间排序算法,在合适的应用场景下能够提供优异的性能表现。通过理解其原理和实现方式,可以在实际编程中更好地选择和应用这种算法。


参考来源

相关推荐
不知名的老吴9 分钟前
后端知识点:Python处理加权点赞
开发语言·python
忡黑梨13 分钟前
eNSP_从直连到BGP全网互通
c语言·网络·数据结构·python·算法·网络安全
Cyber4K26 分钟前
【Python专项】基础语法(2)
开发语言·python
2601_9561394240 分钟前
文旅行业品牌全案公司哪家强
大数据·人工智能·python
hrhcode40 分钟前
【LangGraph】二.State 和 Node 的设计细节
python·ai·langchain·langgraph·ai框架
dfdfadffa1 小时前
如何创建仅在首次订阅时执行一次计算的 RxJS 懒加载 Observable
jvm·数据库·python
m0_624578591 小时前
SQL分组后如何计算移动平均值_利用窗口函数AVG配合ROWS
jvm·数据库·python
2401_824222691 小时前
如何修复待办事项列表无法添加任务的 JavaScript 错误
jvm·数据库·python
CHANG_THE_WORLD1 小时前
<Fluent Python > Unicode 文本与字节
开发语言·python