以下是对归并排序和快速排序的详细解析,包含代码实现与案例演示:
一、归并排序(Merge Sort)
-
算法原理
分治策略: -
分解:将数组递归分成两个子数组(直到单个元素)
-
合并:将有序子数组合并成新的有序数组
-
时间复杂度
| 场景 | 时间复杂度 | 空间复杂度 |
|-----|-----------|-----------|
| 最优 | O(n logn) | O(n) |
| 最差 | O(n logn) | O(n) |
| 平均 | O(n logn) | O(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):
merged = []
i = j = 0
while i < len(left) and j < len(right):
if left[i] <= right[j]:
merged.append(left[i])
i += 1
else:
merged.append(right[j])
j += 1
merged.extend(left[i:])
merged.extend(right[j:])
return merged
- 案例演示
输入数组:[38, 27, 43, 3, 9, 82, 10]
分解过程:
[38, 27, 43, 3] | [9, 82, 10]
[38, 27] | [43, 3] | [9, 82] | [10]
[38] | [27] | [43] | [3] | [9] | [82] | [10]
合并过程:
Level 1:
[27, 38] | [3, 43] | [9, 82] | [10]
Level 2:
[3, 27, 38, 43] | [9, 10, 82]
Final:
[3, 9, 10, 27, 38, 43, 82]
二、快速排序(Quick Sort)
-
算法原理
分治策略: -
分区:选择基准元素,将数组分为两个子数组
-
递归:对左右子数组进行递归排序
-
时间复杂度
| 场景 | 时间复杂度 | 空间复杂度 |
|-----|-----------|-----------|
| 最优 | O(n logn) | O(logn) |
| 最差 | O(n²) | O(n) |
| 平均 | O(n logn) | O(logn) | -
代码实现
def quick_sort(arr, low=0, high=None):
if high is None:
high = len(arr) - 1
if low < high:
pi = partition(arr, low, high)
quick_sort(arr, low, pi-1)
quick_sort(arr, pi+1, high)
return arr
def partition(arr, low, high):
pivot = arr[high]
i = low - 1
for j in range(low, high):
if arr[j] <= pivot:
i += 1
arr[i], arr[j] = arr[j], arr[i]
arr[i+1], arr[high] = arr[high], arr[i+1]
return i+1
- 案例演示
输入数组:[10, 7, 8, 9, 1, 5]
排序过程:
初始状态:10 7 8 9 1 5
第一次分区(pivot=5):
1 5 | 7 8 9 10
左子数组排序:
1(已排序)
右子数组排序:
7 8 9 10 → 分区(pivot=10)
7 8 9 | 10 → 排序完成
最终结果:1 5 7 8 9 10
三、算法对比
特性 | 归并排序 | 快速排序 |
---|---|---|
稳定性 | 稳定 | 不稳定 |
最佳场景 | 链表排序 | 内存敏感型数据 |
最差情况 | 始终O(n logn) | 已排序数组O(n²) |
空间占用 | 需要额外O(n)空间 | 原地排序 |
数据敏感度 | 无 | 依赖pivot选择 |
四、关键差异可视化
归并排序合并过程
原始子数组:[27, 38] 和 [3, 43]
合并步骤:
1. 比较27和3 → 取3
2. 比较27和43 → 取27
3. 比较38和43 → 取38
4. 剩余43 → 合并完成
快速排序分区过程
数组:[10, 7, 8, 9, 1, 5]
分区过程(pivot=5):
i=-1, j=0: 10>5 → 不交换
j=1: 7>5 → 不交换
j=2: 8>5 → 不交换
j=3: 9>5 → 不交换
j=4: 1<=5 → i=0,交换arr[0]和arr[4]
最终交换pivot到i+1位置
掌握这两种分治算法后,可以应对90%的排序场景需求。实际应用中根据数据特征选择:需要稳定性用归并,追求空间效率用快排。