返回
AI领航:漫话归并排序与快速排序
前端
2023-09-28 22:42:55
序言
欢迎来到算法与数据结构的进阶之旅!本文旨在用一种轻松诙谐的方式,为您阐述归并排序和快速排序这两大经典排序算法。
结识归并排序
原理:
- 设想一个参差不齐的海绵体,将它均分成两部分。
- 接着,把每部分的海绵再分成两半,依此类推,直到每个海绵体都变成一块。
- 现在,按照大小依次把这些小海绵体合并起来,就得到了一个有序的海绵体。
流程:
- 将数组划为左右两部分
- 递归地对左右两部分进行排序
- 合并两部分为一个有序数组
复杂度:
- 时间复杂度:O(n log n)
- 空间复杂度:O(n)
邂逅快速排序
原理:
- 挑选数组中一个“哨兵”值(通常是中间值)
- 把比哨兵值小的数放左边,比哨兵值小的数放右边
- 对左右两部分分别进行同样的快速排序
流程:
- 选择一个哨兵值
- 遍历数组,将比哨兵值小的数放左边,比哨兵值小的数放右边
- 递归地对左右两部分进行快速排序
复杂度:
- 平均时间复杂度:O(n log n)
- 空间复杂度:O(1)(不考虑递归栈)
算法比拼
归并排序 | 快速排序 | |
---|---|---|
原理 | 逐段分解、合并 | 哨兵分治、递归 |
时间复杂度 | O(n log n) | O(n log n) |
空间复杂度 | O(n) | O(1) |
适合场景 | 数组较大且有序度较低 | 数组较小或接近有序 |
优化技巧 | 迭代归并排序优化尾递归 | 通过优化减少哨兵值选择误差 |
代码实战
归并排序(python):
def MergeSort(arr: list) -> list:
"""归并排序"""
def Merge(left: list, right: list) -> list:
i, j, ans = 0, 0, []
while i < len(left) and j < len(right):
if left[i] <= right[j]:
ans.append(left[i])
i += 1
else:
ans.append(right[j])
j += 1
ans.append(left[i:])
ans.append(right[j:])
return ans
if not arr:
return []
mid = len(arr) >> 1 # 右位移相当于 //2
return Merge(MergeSort(arr[:mid]), MergeSort(arr[mid:]))
快速排序(python):
def Partition(arr: list, low: int, high: int) -> int:
"""快排切分"""
i = low - 1
pivot = arr[high]
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
def quickSort(arr: list, low: int, high: int) -> None:
"""快速排序"""
if low < high:
pi = Partition(arr, low, high)
# 递归调用
if pi > 0 and pi < len(arr):
arr[:pi], arr[pi+1:] = arr[pi-1:0:-1], arr[pi+1:]
# 切割点左右快速排序
if pi > 1:
if pi-1 > 0:
arr[:pi] = quickSort(arr[:pi], 0, pi-1)
else:
arr[pi] = quickSort([arr[pi]], 0, 0)
if pi+1 < len(arr):
if pi+1 < len(arr)-1:
arr[pi+1:] = quickSort(arr[pi+1:], 0, len(arr)-pi-1)
else:
arr[pi+1:] = quickSort([arr[pi+1]], 0, 0)
进阶探讨
掌握了归并排序和快速排序的基本原理后,我们来看看如何进一步优化:
- 迭代归并排序:优化递归,用循环代替递归
- 快速排序哨兵优化:优化哨兵选择,如使用中位数、在区间内部选取多个哨兵值
总结
归并排序和快速排序可谓算法界的两大巨头,它们既经典又实用。无论是想高效排序大规模无序数据,还是在特定场景下寻求最优方案,它们都是不二之选。
掌握好这两大排序算法,算法进阶之旅才能走得更远,探索数据结构的奥秘也能更加得心应手!