快速排序效率

为了搞清楚快速排序的效率,我们先从分区开始。分解来看,你会发现它包含两种步骤。

❏ 比较:每个值都要与轴做比较。

❏ 交换:在适当时候将左右指针所指的两个值交换位置。

一次分区至少有N次比较,即数组的每个值都要与轴做比较。因为每次分区时,左右指针都会从两端开始靠近,直到相遇。

交换的次数则取决于数据的排列情况。一次分区里,交换最少会有1次,最多会有N / 2次,因为即使所有元素都需要交换,我们也只是将左半部分与右半部分进行交换,如下图所示。

对于随机排列的数据,粗略来算就是N / 2的一半,即N / 4次交换。于是,N次比较加上N / 4次交换,共1.25N步。最后根据大O记法的规则,忽略常数项,得出分区操作的时间为O(N)。

这就是一次分区的效率。但完整的快速排序需要对多个数组以及不同大小的子数组分区,想知道整个过程所花的时间,还要再进一步分析才行。

为了更形象地描述,我们将一个含有8个元素的数组的快速排序过程画了出来。它旁边有每一次分区所作用的元素个数。由于元素值并不重要,因此就不显示了。注意,作用范围就是那些白色的格子。

这里有8次分区,但每次作用的范围大小不一。因为只含1个元素的子数组就是基准情形,无须任何交换和比较,所以只有元素量大于或等于2的子数组才要算分区。

由于此例属于平均情况的一种,因此我们假设每次分区大约要花1.25N步,得出:

如果再对不同大小的数组做统计,你会发现N个元素,就要N×log N步。想体会什么是N×log N的话,可参考下表。

在上面一个数组含8个元素的例子中,快速排序花了大约21步,也很接近8×log8(等于24)​。这种时间复杂度的算法我们还是第一次遇到,用大O记法来表达的话,它是O(N log N)算法。

快速排序的步数接近N×log N绝非偶然。如果我们以更平均的情况来考察快速排序,就能看出原因了。

快速排序开始时会对整个数组进行分区。假设此次分区会将轴最终安放到数组中央——这也是平均情况——然后我们就要对由此切开的两半进行分区。巧合的是,它们的轴也最终落在各自的中央,分出4个大小为原数组四分之一的子数组。并且,接下来所有分区都出现了这种轴在中央的情况。

这样一来,我们基本上就是在不断地对半切分子数组,直至产生出的子数组长度为1。那么,一个数组要经历多少次分区才能切到这么小呢?如果数组元素有N个,那就是log N次。假设元素有8个,那就要对半切3次,才能分出只有1个元素的子数组。这个原理你应该在二分查找那节学过了。对两个新的子数组所执行的分区操作,需要处理的数据量还是相当于对原数组所做的分区。如下图所示。

因为等分发生了log N次,而每次都要对总共N个元素做分区,所以总步数为N×log N。

之前我们看到的很多算法,最佳情况都发生在元素有序的时候。但在快速排序里,最佳情况应该是每次分区后轴都刚好落在子数组的中间。

最坏情况

快速排序最坏的情况就是每次分区都使轴落在数组的开头或结尾。导致这种情况的原因有好几种,包括数组已升序排列,或已降序排列。下面我们把这种情况用图来说明一下。

虽然在此情况下,每次分区都只有一次交换,但比较的次数却变得很多。在轴总落在中央的例子里,每次分区都能划分出比原数组小得多的子数组(过程中产生的最大的子数组长度为4)​,使各部分都能很快地到达基准情形。然而如果轴落在其中一端,前5次分区就需要处理长度大于4的数组。而且这5次分区里,每次所需的比较次数还是和子数组的元素量一样多。

于是在最坏情况下,对8 + 7 + 6 + 5 + 4 + 3 + 2个元素进行分区,一共35次比较。

写成公式的话,就是N个元素,需要N + (N -1) + (N -2) + (N -3) + … + 2步,即$N^{2}$/ 2步,如下图所示。

又因为大O忽略常数,所以最终我们会说,快速排序最坏情况下的效率为O($N^{2}$)。既然把快速排序分析完了,我们将它与插入排序比较一下。

虽然快速排序在最好情况和最坏情况都没能超越插入排序,但在最常遇见的平均情况,前者的O(Nlog N)比后者的O($N^{2}$)好得多,所以总体来说,快速排序优于插入排序。

以下是各种时间复杂度的对比。

由于快速排序在平均情况下表现优异,于是很多编程语言自带的排序函数都采用它来实现。因此一般你不需要自己写快速排序。但你可能需要学会写快速选择——它是一种类似快速排序的实用算法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值