文章目录
本文参考UCAS卜东波老师的计算机算法设计分析课程完成
前言
快速排序是复杂度 O ( n l o g n ) O(nlogn) O(nlogn)的排序算法中最常用的一个,也是分治思想的一个具体应用,关于分治思想的理解可以参考我的这篇文章分治思想。在了解快速排序前,我建议先理解分治思想和归并排序,掌握之后再来看快速排序,会有更好的效果。
快速排序
原理
快速排序与归并排序最明显的不同点是,前者基于数值划分,后者基于下标划分。快速排序会从数组中找一个中间数pivot,将数组小于piovt的放到左边,大于pivot的放到右边。这个貌似很容易理解(先不管pivot如何选取),我们可以得到如下伪代码:
quick_sort(A):
S_l = [],S_r = [] # s_l存储小于pivot的值,s_r存储大于pivot的值
choose pivot A[p] # 随机抽取
for i = 0 to |A|-1:
if A[i] < A[p]:
S_l += A[i] # 若比pivot小,则将A[i]放到pivot左边
else:
S_r += A[i] # 否则将A[i]放到pivot右边
quick_sort(S-)
quick_sort(S+)
output S-,A[p],S+ # 按照顺序输出三者
将上面的过程转换成图例如下:

第一次pivot选择4(随机),213放左边,5放右边,第二次pivot选择3,21放左边,右边为空,第三次pivot选择1,左边为空,2放右边。得到有序数组。
时间复杂度
- 估算时间复杂度
上述过程的时间复杂度是多少呢?好像是 O ( n l o g n ) O(nlogn) O(nlogn)?我们考虑两种极端情况,pivot每次都选中了中位数和pivot每次都选了边边的数。两种划分的结果如下:

发现时间相差较大,写出递推公式分别如下(每一次选定pivot,所有数要和其比较,额外开销时间复杂度 O ( n ) O(n) O(n)):- 最好情况
T ( n ) = 2 T ( n 2 ) + O ( n ) = O ( n l o g n ) T(n)=2T(\frac{n}{2})+O(n) = O(nlogn) T(n)=2T(2n)+O(n)=O(nlogn) - 最坏情况
T ( n ) = T ( n − 1 ) + O ( n ) = O ( n 2 ) T(n)=T(n-1)+O(n) = O(n^2) T(n)=T(n−1)+O(n)=O(n2)
- 最好情况
那么一般情况下是什么样的呢?
假设取pivot的时候使得划分比例是3:1,那么划分得到的树如下所示(也就是分治思想一文中提到的不均匀划分):

容易知道这棵树的高度是 l o g 4 3 n log_\frac{4}{3}n log34n,由于每一次划分的额外开销是 O ( n ) O(n) O(n)所以总的时间复杂度是 O ( n l o g 4 3 n ) = O ( n l o g n ) O(nlog_\frac{4}{3}n)=O(nlogn) O(nlog34n)=O(nlogn),和最好情况一样的复杂度,同样的,按8:1,100:1的划分也都有 O ( n l o g 9 8 n ) = O ( n l o g 101 100 n ) = O ( n l o g n ) O(nlog_\frac{9}{8}n)=O(nlog_\frac{101}{100}n)=O(nlogn) O(nlog89n)=O(nlog100101n)=O(nlogn)
有人可能不理解这里,为什么划分100:1这么大,仍然复杂度还是 O ( n l o g n ) O(nlogn) O(nlog

本文详细解析快速排序算法的原理、时间复杂度,并探讨了如何通过选择pivot来优化效率。通过实例分析,展示了快速排序在不同情况下的时间复杂度,并推导出期望时间复杂度为O(nlogn)。此外,提出了随机选择pivot和多点取中位数等优化策略,以及简单快速排序的Python实现。
2186

被折叠的 条评论
为什么被折叠?



