十大经典排序算法全解析:原理、实现与优化指南

十大经典排序算法全解析:原理、实现与优化指南

排序算法是计算机科学的核心基础之一,其效率直接影响数据处理、搜索优化、数据库查询等场景的性能。本文将系统梳理十大经典排序算法,从原理、实现到优化策略进行全方位解析,帮助开发者根据业务需求选择最优方案。

一、基础排序算法:简单但低效

1. 冒泡排序(Bubble Sort)

原理:通过相邻元素的比较与交换,将最大值逐步“冒泡”至数组末尾。
实现

  1. def bubble_sort(arr):
  2. n = len(arr)
  3. for i in range(n):
  4. for j in range(0, n-i-1):
  5. if arr[j] > arr[j+1]:
  6. arr[j], arr[j+1] = arr[j+1], arr[j] # 交换

优化点

  • 增加标志位swapped,若某一轮未发生交换,则提前终止。
  • 时间复杂度:最优O(n)(已排序),最差O(n²)。
  • 适用场景:小规模数据或教学演示。

2. 选择排序(Selection Sort)

原理:每次选择未排序部分的最小值,与当前位置交换。
实现

  1. def selection_sort(arr):
  2. n = len(arr)
  3. for i in range(n):
  4. min_idx = i
  5. for j in range(i+1, n):
  6. if arr[j] < arr[min_idx]:
  7. min_idx = j
  8. arr[i], arr[min_idx] = arr[min_idx], arr[i] # 交换

特点

  • 交换次数少(最多n-1次),但比较次数多。
  • 时间复杂度:始终O(n²)。
  • 适用场景:交换成本高的场景(如链表)。

3. 插入排序(Insertion Sort)

原理:将未排序元素插入已排序部分的正确位置。
实现

  1. def insertion_sort(arr):
  2. for i in range(1, len(arr)):
  3. key = arr[i]
  4. j = i-1
  5. while j >= 0 and key < arr[j]:
  6. arr[j+1] = arr[j] # 元素后移
  7. j -= 1
  8. arr[j+1] = key # 插入

优化点

  • 二分查找优化插入位置(减少比较次数)。
  • 时间复杂度:最优O(n),最差O(n²)。
  • 适用场景:部分有序或小规模数据。

二、高效排序算法:分治与递归

4. 归并排序(Merge Sort)

原理:采用分治法,将数组递归拆分为两半,分别排序后合并。
实现

  1. def merge_sort(arr):
  2. if len(arr) > 1:
  3. mid = len(arr) // 2
  4. left = arr[:mid]
  5. right = arr[mid:]
  6. merge_sort(left) # 递归左半
  7. merge_sort(right) # 递归右半
  8. i = j = k = 0
  9. while i < len(left) and j < len(right):
  10. if left[i] < right[j]:
  11. arr[k] = left[i]
  12. i += 1
  13. else:
  14. arr[k] = right[j]
  15. j += 1
  16. k += 1
  17. # 处理剩余元素
  18. while i < len(left):
  19. arr[k] = left[i]
  20. i += 1
  21. k += 1
  22. while j < len(right):
  23. arr[k] = right[j]
  24. j += 1
  25. k += 1

特点

  • 稳定排序,适合链表或外部排序(如大数据处理)。
  • 时间复杂度:始终O(n log n)。
  • 空间复杂度:O(n)(需额外存储)。

5. 快速排序(Quick Sort)

原理:选择基准值(pivot),将数组分为小于和大于基准的两部分,递归排序。
实现

  1. def quick_sort(arr, low, high):
  2. if low < high:
  3. pi = partition(arr, low, high) # 获取分区点
  4. quick_sort(arr, low, pi-1) # 递归左半
  5. quick_sort(arr, pi+1, high) # 递归右半
  6. def partition(arr, low, high):
  7. pivot = arr[high] # 选择最后一个元素为基准
  8. i = low - 1
  9. for j in range(low, high):
  10. if arr[j] <= pivot:
  11. i += 1
  12. arr[i], arr[j] = arr[j], arr[i] # 交换
  13. arr[i+1], arr[high] = arr[high], arr[i+1] # 基准归位
  14. return i + 1

优化点

  • 三数取中法选择基准,避免最坏情况。
  • 小规模数据切换为插入排序。
  • 时间复杂度:平均O(n log n),最差O(n²)。
  • 适用场景:大规模随机数据。

三、特殊场景优化算法

6. 堆排序(Heap Sort)

原理:利用最大堆(或最小堆)进行排序,每次取出堆顶元素并调整堆。
实现

  1. def heapify(arr, n, i):
  2. largest = i
  3. left = 2 * i + 1
  4. right = 2 * i + 2
  5. if left < n and arr[left] > arr[largest]:
  6. largest = left
  7. if right < n and arr[right] > arr[largest]:
  8. largest = right
  9. if largest != i:
  10. arr[i], arr[largest] = arr[largest], arr[i] # 交换
  11. heapify(arr, n, largest) # 递归调整
  12. def heap_sort(arr):
  13. n = len(arr)
  14. # 构建最大堆
  15. for i in range(n//2 - 1, -1, -1):
  16. heapify(arr, n, i)
  17. # 逐个提取堆顶
  18. for i in range(n-1, 0, -1):
  19. arr[i], arr[0] = arr[0], arr[i] # 交换堆顶与末尾
  20. heapify(arr, i, 0) # 调整剩余堆

特点

  • 不稳定排序,但空间复杂度O(1)。
  • 时间复杂度:始终O(n log n)。
  • 适用场景:内存受限的嵌入式系统。

7. 希尔排序(Shell Sort)

原理:通过分组插入排序逐步缩小间隔,最终完成整体排序。
实现

  1. def shell_sort(arr):
  2. n = len(arr)
  3. gap = n // 2
  4. while gap > 0:
  5. for i in range(gap, n):
  6. temp = arr[i]
  7. j = i
  8. while j >= gap and arr[j-gap] > temp:
  9. arr[j] = arr[j-gap]
  10. j -= gap
  11. arr[j] = temp
  12. gap //= 2 # 缩小间隔

特点

  • 插入排序的改进版,时间复杂度介于O(n)和O(n²)之间。
  • 适用场景:中等规模数据。

四、非比较排序算法

8. 计数排序(Counting Sort)

原理:统计每个元素的出现次数,按顺序输出。
实现

  1. def counting_sort(arr):
  2. max_val = max(arr)
  3. count = [0] * (max_val + 1)
  4. for num in arr:
  5. count[num] += 1
  6. # 重建有序数组
  7. sorted_arr = []
  8. for i in range(len(count)):
  9. sorted_arr.extend([i] * count[i])
  10. return sorted_arr

特点

  • 仅适用于整数且范围较小的数据。
  • 时间复杂度:O(n + k)(k为数据范围)。
  • 适用场景:年龄、分数等有限范围数据。

9. 桶排序(Bucket Sort)

原理:将数据分到多个桶中,对每个桶单独排序后合并。
实现

  1. def bucket_sort(arr, bucket_size=5):
  2. min_val, max_val = min(arr), max(arr)
  3. bucket_count = (max_val - min_val) // bucket_size + 1
  4. buckets = [[] for _ in range(bucket_count)]
  5. # 分桶
  6. for num in arr:
  7. index = (num - min_val) // bucket_size
  8. buckets[index].append(num)
  9. # 对每个桶排序(此处用内置排序)
  10. sorted_arr = []
  11. for bucket in buckets:
  12. sorted_arr.extend(sorted(bucket))
  13. return sorted_arr

特点

  • 依赖桶的均匀分布,否则效率下降。
  • 时间复杂度:平均O(n + k)。
  • 适用场景:均匀分布的浮点数。

10. 基数排序(Radix Sort)

原理:按位数从低位到高位依次排序(可用计数排序实现)。
实现

  1. def counting_sort_for_radix(arr, exp):
  2. n = len(arr)
  3. output = [0] * n
  4. count = [0] * 10
  5. # 统计当前位数字
  6. for i in range(n):
  7. index = (arr[i] // exp) % 10
  8. count[index] += 1
  9. # 计算累计位置
  10. for i in range(1, 10):
  11. count[i] += count[i-1]
  12. # 反向填充输出数组
  13. i = n - 1
  14. while i >= 0:
  15. index = (arr[i] // exp) % 10
  16. output[count[index] - 1] = arr[i]
  17. count[index] -= 1
  18. i -= 1
  19. # 复制回原数组
  20. for i in range(n):
  21. arr[i] = output[i]
  22. def radix_sort(arr):
  23. max_val = max(arr)
  24. exp = 1
  25. while max_val // exp > 0:
  26. counting_sort_for_radix(arr, exp)
  27. exp *= 10

特点

  • 仅适用于整数或固定长度的字符串。
  • 时间复杂度:O(d(n + k))(d为最大位数)。
  • 适用场景:电话号码、ID等固定位数数据。

五、算法选择指南

  1. 小规模数据:插入排序或选择排序。
  2. 大规模随机数据:快速排序(优化后)。
  3. 稳定排序需求:归并排序或计数排序。
  4. 内存受限场景:堆排序。
  5. 有限范围整数:计数排序或基数排序。

通过理解算法原理与适用场景,开发者可针对具体问题设计高效的数据处理流程,提升系统整体性能。