分类目录:《算法设计与分析》总目录
在《快速排序-[快速排序的性能]》中,我们给出了在最坏情况下快速排序性能的直观分析,以及它速度比较快的原因。在本文中,我们要给出快速排序性能的更严谨的分析。我们首先从最坏情况分析开始,其方法可以用于原版和随机化版本的quick_sort(arr,low,high)
的分析,然后给出随机化版本的quick_sort(arr,low,high)
的期望运行时间。
在《快速排序-[快速排序的性能]》中,我们得到在最坏情况下,快速排序的每一层递归的时间复杂度是
Θ
(
n
2
)
\Theta(n^2)
Θ(n2)。我们也从直观上了解了为什么随机化版本的quick_sort(arr,low,high)
的期望运行时间是
O
(
n
lg
n
)
O(n\lg n)
O(nlgn)。
如果在递归的每一层上,randomized_partition(arr,low,high)
将任意常数比例的元素划分到一个子数组中,则算法的递归树的深度为
Θ
(
log
n
)
\Theta(\log n)
Θ(logn),并且每一层上的工作量都是
O
(
n
)
O(n)
O(n)。即使在最不平衡的划分情况下,会增加一些新的层次,但总的运行时间仍然保持是
O
(
n
log
n
)
O(n\log n)
O(nlogn)。要准确地分析随机化版本的quick_sort(arr,low,high)
的期望运行时间,首先要理解划分操作是如何进行的;然后,在此基础之上,推导出期望运行时间的一个
O
(
lg
n
)
O(\lg n)
O(lgn)的界。有了这一期望运行时间的上界,再加《快速排序-[快速排序的性能]》中得到的最好情况界
O
(
lg
n
)
O(\lg n)
O(lgn),我们就能得到
O
(
lg
n
)
O(\lg n)
O(lgn)这一期望运行时间。在这里,假设待排序的元素始终是互异的。
运行时间和比较操作
原版和随机化版本的quick_sort(arr,low,high)
除了如何选择主元元素有差异以外,其他方面完全相同。因此,我们可以在讨论quick_sort(arr,low,high)
和partition(arr,low,high)
的基础上分析randomized_partition(arr,low,high)
。
quick_sort(arr,low,high)
的运行时间是由在partition(arr,low,high)
操作上所花费的時间浃是的。每次对partition(arr,low,high)
的调用时,都会选择一个主元元素,而且该元素不会被包含在后续的对quick_sort(arr,low,high)
的和partition(arr,low,high)
的递归调用中。因此,在快速排序算法的整个执行期间,至多只可能调用partition(arr,low,high)
操作
n
n
n次。调用一次 partition(arr,low,high)
的时间为
O
(
1
)
O(1)
O(1)再加上一段循环时间这段时间与partition(arr,low,high)
中for
循环的迭代次数成正比。这一for
循环的每一轮迭代都要进行一次比较:比较主元元素与数组arr
中另一个元素。因此,如果我们可以统计执行的总次数,就能够给出在 quick_sort(arr,low,high)
的执行过程中,for
循环所花时间的界了。
我们还可以很容易地得出:当在一个包含
n
n
n个元素的数组上运行quick_sort(arr,low,high)
时,假设在partition(arr,low,high)
的比较的次数为
X
X
X,那么quick_sort(arr,low,high)
的运行时间为
O
(
n
+
X
)
O(n+X)
O(n+X)。那么对于随机化版本的quick_sort(arr,low,high)
,它的时间复杂度为
O
(
n
lg
n
)
O(n \lg n)
O(nlgn)。