以下是 常见排序算法 的详细整理,涵盖原理、时间复杂度、稳定性及代码实现(Python示例),附对比总结表:
1. 基础排序算法
(1) 冒泡排序(Bubble Sort)
-
原理:依次比较相邻元素,将较大的元素“冒泡”到右侧。
-
时间复杂度:平均和最坏
O(n²),最好O(n)(已排序时)。 -
稳定性:稳定。
-
代码:
def bubble_sort(arr): n = len(arr) for i in range(n): swapped = False for j in range(0, n-i-1): if arr[j] > arr[j+1]: arr[j], arr[j+1] = arr[j+1], arr[j] swapped = True if not swapped: # 提前终止优化 break return arr
(2) 选择排序(Selection Sort)
-
原理:每次从未排序部分选择最小元素,放到已排序末尾。
-
时间复杂度:始终
O(n²)。 -
稳定性:不稳定(交换可能破坏顺序)。
-
代码:
def selection_sort(arr): n = len(arr) for i in range(n): min_idx = i for j in range(i+1, n): if arr[j] < arr[min_idx]: min_idx = j arr[i], arr[min_idx] = arr[min_idx], arr[i] return arr
(3) 插入排序(Insertion Sort)
-
原理:将未排序元素逐个插入已排序部分的正确位置。
-
时间复杂度:平均和最坏
O(n²),最好O(n)。 -
稳定性:稳定。
-
代码:
def insertion_sort(arr): for i in range(1, len(arr)): key = arr[i] j = i-1 while j >=0 and key < arr[j]: arr[j+1] = arr[j] j -= 1 arr[j+1] = key return arr
2. 高效排序算法
(1) 快速排序(Quick Sort)
-
原理:分治法,选取基准(pivot),将小于基准的放左边,大于的放右边,递归处理子数组。
-
时间复杂度:平均
O(n log n),最坏O(n²)(已排序时,若基准选择不当)。 -
稳定性:不稳定。
-
代码:
def quick_sort(arr): if len(arr) <= 1: return arr pivot = arr[len(arr)//2] # 基准选择中间元素 left = [x for x in arr if x < pivot] middle = [x for x in arr if x == pivot] right = [x for x in arr if x > pivot] return quick_sort(left) + middle + quick_sort(right)
(2) 归并排序(Merge Sort)
-
原理:分治法,递归分割数组至单个元素,再合并有序子数组。
-
时间复杂度:始终
O(n log n)。 -
稳定性:稳定。
-
代码:
def merge_sort(arr): if len(arr) <= 1: return arr mid = len(arr) // 2 left = merge_sort(arr[:mid]) right = merge_sort(arr[mid:]) return merge(left, right) def merge(left, right): res = [] i = j = 0 while i < len(left) and j < len(right): if left[i] <= right[j]: res.append(left[i]) i += 1 else: res.append(right[j]) j += 1 res.extend(left[i:]) res.extend(right[j:]) return res
(3) 堆排序(Heap Sort)
-
原理:将数组构建为大顶堆,依次取出堆顶元素(最大值)并调整堆。
-
时间复杂度:始终
O(n log n)。 -
稳定性:不稳定。
-
代码:
def heap_sort(arr): def heapify(arr, n, i): largest = i left = 2*i + 1 right = 2*i + 2 if left < n and arr[left] > arr[largest]: largest = left if right < n and arr[right] > arr[largest]: largest = right if largest != i: arr[i], arr[largest] = arr[largest], arr[i] heapify(arr, n, largest) n = len(arr) # 构建大顶堆 for i in range(n//2-1, -1, -1): heapify(arr, n, i) # 逐个提取元素 for i in range(n-1, 0, -1): arr[i], arr[0] = arr[0], arr[i] heapify(arr, i, 0) return arr
3. 非比较排序
(1) 计数排序(Counting Sort)
-
适用场景:整数排序,且数据范围
k较小(如0~100)。 -
时间复杂度:
O(n + k),k为数据范围。 -
稳定性:稳定。
-
代码:
def counting_sort(arr): max_val = max(arr) count = [0] * (max_val + 1) for num in arr: count[num] += 1 res = [] for i in range(len(count)): res.extend([i] * count[i]) return res
(2) 基数排序(Radix Sort)
-
原理:按位数从低位到高位依次进行稳定排序(通常用计数排序)。
-
时间复杂度:
O(d(n + k)),d为最大位数,k为基数(如10进制时为10)。 -
稳定性:稳定。
-
代码:
def radix_sort(arr): max_num = max(arr) exp = 1 while max_num // exp > 0: counting_sort_by_digit(arr, exp) exp *= 10 return arr def counting_sort_by_digit(arr, exp): n = len(arr) output = [0] * n count = [0] * 10 for num in arr: digit = (num // exp) % 10 count[digit] += 1 for i in range(1, 10): count[i] += count[i-1] for i in range(n-1, -1, -1): digit = (arr[i] // exp) % 10 output[count[digit]-1] = arr[i] count[digit] -= 1 for i in range(n): arr[i] = output[i]
对比总结表
| 算法 | 平均时间复杂度 | 最坏时间复杂度 | 空间复杂度 | 稳定性 | 适用场景 |
|---|---|---|---|---|---|
| 冒泡排序 | O(n²) | O(n²) | O(1) | 稳定 | 教学或小规模数据 |
| 选择排序 | O(n²) | O(n²) | O(1) | 不稳定 | 简单实现,非主流应用 |
| 插入排序 | O(n²) | O(n²) | O(1) | 稳定 | 小规模或基本有序数据 |
| 快速排序 | O(n log n) | O(n²) | O(log n) | 不稳定 | 通用排序,平均性能最优 |
| 归并排序 | O(n log n) | O(n log n) | O(n) | 稳定 | 大数据、外部排序、链表排序 |
| 堆排序 | O(n log n) | O(n log n) | O(1) | 不稳定 | 原地排序,内存受限场景 |
| 计数排序 | O(n + k) | O(n + k) | O(n + k) | 稳定 | 整数且范围小(如年龄、分数) |
| 基数排序 | O(d(n + k)) | O(d(n + k)) | O(n + k) | 稳定 | 多关键字整数(如手机号) |
应用建议
-
通用场景:优先选择快速排序(需随机化基准避免最坏情况)。
-
稳定性要求:选择归并排序或计数/基数排序。
-
内存受限:堆排序(原地排序,无需额外空间)。
-
小规模数据:插入排序(常数因子小,实际更快)。
学习资源
掌握排序算法是理解算法设计与分析的基础,建议通过手写代码和复杂度分析加深理解!