基数排序原理与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 小时前
算法与设计与分析-习题4.2
算法·排序算法·深度优先·dfs·bfs
Storynone10 小时前
【Day20】LeetCode:39. 组合总和,40. 组合总和II,131. 分割回文串
python·算法·leetcode
小鸡吃米…11 小时前
Python—— 环境搭建
python
io_T_T11 小时前
python 文件管理库 Path 解析(详细&基础)
python
渔阳节度使12 小时前
SpringAI实时监控+观测性
后端·python·flask
铁手飞鹰12 小时前
Visual Studio创建Cmake工程导出DLL,通过Python调用DLL
android·python·visual studio
飞Link13 小时前
告别盲目找Bug:深度解析 TSTD 异常检测中的预测模型(Python 实战版)
开发语言·python·算法·bug
7yewh13 小时前
jetson_yolo_deployment 02_linux_dev_skills
linux·python·嵌入式硬件·yolo·嵌入式
love530love14 小时前
ComfyUI rgthree-comfy Image Comparer 节点无输出问题排查与解决
人工智能·windows·python·comfyui·rgthree-comfy·nodes 2.0·vue 节点