分类目录:《算法设计与分析》总目录
相关文章:
· 排序算法(一):插入排序
· 排序算法(二):归并排序
· 排序算法(三):堆排序
· 排序算法(四):选择排序
· 排序算法(五):冒泡排序
· 排序算法(六):希尔排序
· 排序算法(七):快速排序
\qquad
· ①基础知识
\qquad
· ②快速排序的性能
\qquad
· ③快速排序的随机化
\qquad
· ④快速排序的分析
· 排序算法(八):计数排序
· 排序算法(九):基数排序
· 排序算法(十):桶排序
· 排序算法:比较排序算法的下界
· 排序算法:十大排序算法总结
对于包含 n n n个数的输入数组来说,快速排序是一种最坏情况时间复杂度为 Θ ( n 2 ) \Theta(n^2) Θ(n2)的排序算法。虽然最坏情况时间复杂度很差,但是快速排序通常是实际排序应用中最好的选择,因为它的平均性能非常好:它的期望时间复杂度是 O ( n lg n ) O(n\lg n) O(nlgn),而且 O ( n lg n ) O(n\lg n) O(nlgn)中隐含的常数因子非常小。另外,它还能够进行原址排序,甚至在虚存环境中也能很好地工作。
《排序算法(七):快速排序-[基础知识]》将描述快速排序算法及它的一个重要的划分子程序。因为快速排序的运行情况比较复杂,在《排序算法(七):快速排序-[快速排序的性能]》中,我们先对其性能进行一个直观的讨论,在《快速排序》系列文章的最后会给出一个准确的分析。在《排序算法(七):快速排序-[快速排序的随机化版本]》中,我们会介绍一个基于随机抽样的快速排序算法。这一算法的期望时间复杂度较好,而且没有什么特殊的输入会导致最坏情况的发生。《排序算法(七):快速排序-[分析快速排序]》对这一随机算法的分析表明,其最坏情况时间复杂度是 Θ ( n 2 ) \Theta(n^2) Θ(n2),在元素互异的情况下,期望时间复杂度 O ( n lg n ) O(n\lg n) O(nlgn)。
与归并排序一样,快速排序也使用了《分治策略(一):基础知识》介绍的分治思想。下面是对一个典型的子数组 A A A进行快速排序的三步分治过程:
- 分解:数组 A [ p ⋯ r ] A[p\cdots r] A[p⋯r]被划分为两个(可能为空)子数组 A [ p ⋯ q − 1 ] A[p\cdots q-1] A[p⋯q−1]和 A [ q + 1 ⋯ r ] A[q+1\cdots r] A[q+1⋯r],使得 A [ p ⋯ q − 1 ] A[p\cdots q-1] A[p⋯q−1]中的每一个元素都小于等于 A [ q ] A[q] A[q],而 A [ q ] A[q] A[q]也小于等于 A [ q + 1 ⋯ r ] A[q+1\cdots r] A[q+1⋯r]中的每个元素。其中,计算下标 q q q也是划分过程的一部分。
- 解决:通过递归调用快速排序,对子数组 A [ p ⋯ q − 1 ] A[p\cdots q-1] A[p⋯q−1]和 A [ q + 1 ⋯ r ] A[q+1\cdots r] A[q+1⋯r]进行排序。
- 合并:因为子数组都是原址排序的,所以不需要合并操作:数组 A [ p ⋯ r ] A[p\cdots r] A[p⋯r]已经有序。
下面的程序实现快速排序:
def partition(arr,low,high):
i = low-1
pivot = arr[high]
for j in range(low, high):
if arr[j] <= pivot:
i = i+1
arr[i],arr[j] = arr[j],arr[i]
arr[i+1],arr[high] = arr[high],arr[i+1]
return i+1
# 快速排序函数
def quick_sort(arr,low,high):
if low < high:
pi = partition(arr,low,high)
quick_sort(arr, low, pi-1)
quick_sort(arr, pi+1, high)
return arr
最后,我们用动图演示一下插入排序的全过程: