快速排序详解
快速排序,顾名思义,是一种排序速度非常快的排序方法,该算法之所以非常快,是因为高度优化的内部循环,该算法在实际应用中非常广泛。今天我们聊聊快速排序
排序思想
算法中也常常将速度列为非常重要的一个指标,排序算法中的快速排序也是因为它的快而出名
快速排序是一种采用分治思想,在实践中通常运行较快一种排序算法,它的思路如下
对于一个无序数组(排序前先将数组随机打乱)
首先,任意选取一个元素(这里选择数组第一个元素),该元素称为中轴元素
然后将大于或者等于中轴元素的元素放在右边,小于或者等于中轴元素的元素放在左边
上面两个过程(选元素和调整位置)称为分割(partition)
然后对左右两个子数组分别按照同样的方法进行分割操作(递归进行)
一直递归分割到子数组只有一个或零个元素为止,此时整个数组有序
最坏情况
对于规模为N的数组
如果数组有序的话,此时是最坏情况,因为每次递归右子数组规模只比原数组减一,这样递归次数就会很多
每次分割后,数组都会被划分一个大小为0的子数组和原数组大小减一的子数组
设规模为排序规模为N的数组所花费的时间为T(N)
那么T(N)应该等于分割时所花的时间加上左右子数组所花的时间,而分割时会遍历整个数组,所花的时间为O(N)
则可以得到T(N)=T(0)+T(N-1)+O(N)
处理数组大小为0或1所花费的时间为:
T(0) = T(1) = 1;
O(N)=N;
现在只需要算出T(N)即可
T(N) = T(0)+T(N-1)+O(N)
T(N-1) = T(0)+T(N-2)+O(N-1)
T(N-2) = T(0)+T(N-3)+O(N-2)
T(N-3) = T(0)+T(N-4)+O(N-3)
...
T(2) = T(0)+T(1)+O(2)
相加得:
排序前先将数组随机打乱就是防止输入为有序数组而导致排序效率低下,随机打乱将这种可能性(有序)降为极低
最好情况
最好情况就是每次选到一个中轴元素刚好位于中间,此时两个子数组刚好是原数组的一半,那么
T(N)= 2*T(N/2)+O(N)
因为N是2的幂,所以N可以写成,所以从N到2,就是到2^n,所以
一共有k个等式,k个1,而且N=,则k=当底n不是2时几乎一样,所以可以表示成lognN
则 T(N)=N+NlogN=0(NlogN)
平均情况:
T(N)=
[
T(0)+T(N-1)+O(N)+轴在第一个元素位置
T(1)+T(N-2)+O(N)+轴在第二个元素位置
T(2)+T(N-3)+O(N)+轴在第三个元素位置
....
T(N-1)+T(0)+O(N)轴在第N个元素位置
]
所以
平均时间复杂度分析比较困难,分割操作后中轴元素会落在哪里(排序好的位置)?会落在数组的任意位置。假设是等概率落在了数组的任意位置
此时时间复杂度就是将所有可能情况加起来除以N
由数学归纳法可得:
T(N)=O(NlogN)
具体证明过程就不在此证明了,感兴趣的伙伴可参考《数据结构与算法分析》一书或其他资料
恩恩,不错
师傅,我看快排时间复杂度也是O(nlogn),并且最坏情况下可能为O(n^2),为什么说它块呢?
快排之所以块,就是因为它高度优化的内部循环(分割),它既不像归并那样需要辅助数组来回复制元素,也不像堆排序无法利用缓存并且有许多无用的比较,并且最坏情况可以采用一些方法避免
哦,原来这样
关于时间复杂度可看:
稳定性
不是稳定的,因为在整个扫描结束时,中轴元素与arr[j]发生交换的时候,可能破坏稳定性