在面试富途的时候面试官问了这样一个问题:快速排序最坏的情况啥时候出现?当时没有答上来。实际上这个问题比较容易想清楚,思路如下,从快速排序的形式入手:$O(N*logN)$,N 代表单次排序的时间花销,logN 代表递归次数。我们知道最坏情况是$O(N^2)$,也就是说$logN$退化成了$N$。那么什么情况会退化成$logN$,当然是问题规模缩减得慢的时候,这与我们选中枢有直接的关系。假如我们选的中枢,每次都是最小或者最大,那么问题的缩小速度就会变成线性的了;而假如我们选的中枢,每次恰好是中间那个数,那么问题递归次数就是$log_2^N$了。
由于我们一般都是选第一个或者最后一个元素做中枢,那么最坏的情况对应就是:已经有序(这包括正序,逆序,以及全部元素相等)
由于快速排序的这个特征,所以我们一般的算法库中是结合了好几种排序算法:C++一道深坑面试题:STL 里 sort 算法用的是什么排序算法?
同时我也在思考为啥快排这种最坏是$O(N^2)$的算法会被使用,而不直接使用最坏是$O(NlogN)$的算法,比如归并排序,堆排序。答案自然是这些排序也有各自的缺点,而且我估计是无法容忍的缺点。比如归并排序,它不是一个原地排序算法,需要额外的存储空间。堆排序,需要构建堆花费额外的时间。堆构建完毕后,借用堆这种结构,每次只能从堆顶取出最大或最小的数,而且取完还要进行堆维护,花费$logN$的时间。构建堆的过程和堆排序的过程类似,只不过构建堆是添加叶节点+上浮堆化的过程,而堆排序是取根节点+下沉堆化的过程,同样的构建堆也要花费$O(NlogN)$的时间。所以堆排序会花费双倍的时间。