快速排序是一种时间复杂度为 O(n^2) 的排序算法。虽然最坏情况时间复杂度很差,但他的平均性能却很好,它的期望时间复杂度是 O(nlgn) 而且 O(nlgn) 中隐含的常数因子很小大约是1.44左右。
快速排序与归并排序一样,也是基于归并的思想以下是对其子数组 A[ p…r ] 进行快速排序三步分治的过程:
分解:数组 A[ p…r ] 被划分为两个子数组 A[ p…q-1] 和 A[q+1…r],使得 A[ p…q-1]中的每一个元素都小于等于 A[ q ] ,而 A[ q ]也小于等于 A[ q+1…r]中的每一个元素。
解决:通过递归调用快速排序,对子数组A[ p…q-1] 和 A[q+1…r]进行排序。
合并:因为子数组都是原址排序的,所以并不需要合并操作:A[ p…r ] 已经有序。
快速排序伪代码:
QUICKSORT(A,p,r)
if p < r
q = PARTITION(A, p ,r)
QUICKSORT(A, p ,q-1)
QUICKSORT(A, q+1 ,r)
其中,q = PARTITION(A, p ,r) 所执行的操作就是分解操作,并返回 q。
PARTITION函数伪代码:
PARTITION(A, p, r)
x = A[r]
i = p - 1
for j = p to r - 1
do if A[j] ≤ x
then i = i + 1
exchange A[i] with A[j]
exchange A[i + 1] with A[r]
return i + 1
PARTITION函数思路简介:
其中 0 - i 维护的是小于等于A[ r ] 的序列,A[ i+1 ] 即为比 A[ r ] 大的第一个数,j从开始节点遍历到倒数第二个节点,遇到比 A[ r ] 小的数便进行 A[ j ] 与 A[ i+1 ] 的交换,以此维护了 0 - i 序列中比 A[ r ]小的特性。j 遍历完成后,即实现了A[0…i] 小于等于 A[ r ] ,A[i+1…j] 大于 A[ r ]。
PARTITION函数执行过程:
# include
using namespace std;
int PARTITION(int A[],int p,int r)
{
int x = A[r];
int i = p - 1;
for(int j = p; j <= r - 1; j++)
{
if(A[j] <= x)
{
i = i + 1;
swap(A[i],A[j]);
}
}
swap(A[i+1] , A[r]);
return i+1;
}
void QUICKSORT(int A[],int p,int r)
{
if(p < r)
{
int q = PARTITION(A,p,r);
QUICKSORT(A,p,q-1);
QUICKSORT(A,q+1,r);
}
}
int main()
{
int A[100010];
int n;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>A[i];
}
QUICKSORT(A,0,n-1);
for(int i=0;i<n;i++)
{
cout<<A[i]<<" ";
}
return 0;
}
因为无法举出使快速排序达到最坏情况的例子所以我们通过两步证明其最坏时间复杂度为 O( n^2 )
设
T
(
n
)
T (n)
T(n) 为输入规模为 n 时 QUICKSORT 算法的平均运行时间,
T
k
(
n
)
T_k(n)
Tk(n)为所选划分元序号为 k+1 时 QUICKSORT 算法的平均运行时间,则
T
(
n
)
T (n)
T(n) 满足以下递归方程:
T
(
n
)
=
∑
k
=
0
n
−
1
(
p
(
k
+
1
)
T
k
(
n
)
)
T(n)=\sum_{k=0}^{n-1} (p(k+1)T_k(n))
T(n)=k=0∑n−1(p(k+1)Tk(n))其中
p
(
k
+
1
)
p(k+1)
p(k+1)为划分元素序号为
k
+
1
k+1
k+1的概率,我们可以知道划分元素序号的概率是相同的故:
p
(
k
+
1
)
=
1
n
p(k+1)=\frac{1}{n}
p(k+1)=n1,带入上式可得:
T
(
n
)
=
∑
k
=
0
n
−
1
1
n
T
k
(
n
)
)
=
1
n
∑
k
=
0
n
−
1
(
T
(
k
)
+
T
(
n
−
k
−
1
)
+
c
n
)
T(n)=\sum_{k=0}^{n-1} \frac{1}{n}T_k(n))= \frac{1}{n}\sum_{k=0}^{n-1} (T(k)+T(n-k-1)+cn)
T(n)=k=0∑n−1n1Tk(n))=n1k=0∑n−1(T(k)+T(n−k−1)+cn)继续化简可得:
1
n
(
∑
k
=
0
n
−
1
T
(
k
)
+
∑
k
=
0
n
−
1
T
(
n
−
k
−
1
)
)
+
c
n
=
2
n
∑
k
=
0
n
−
1
T
(
k
)
+
c
n
\frac{1}{n}(\sum_{k=0}^{n-1} T(k)+\sum_{k=0}^{n-1}T(n-k-1))+cn=\frac{2}{n}\sum_{k=0}^{n-1}T(k)+cn
n1(k=0∑n−1T(k)+k=0∑n−1T(n−k−1))+cn=n2k=0∑n−1T(k)+cn解递归方程可得:
n
T
(
n
)
=
2
∑
k
=
0
n
−
1
T
(
k
)
+
c
n
2
nT(n)=2\sum_{k=0}^{n-1}T(k)+cn^2
nT(n)=2k=0∑n−1T(k)+cn2
(
n
−
1
)
T
(
n
−
1
)
=
2
∑
k
=
0
n
−
1
T
(
k
)
+
c
n
2
(n-1)T(n-1)=2\sum_{k=0}^{n-1}T(k)+cn^2
(n−1)T(n−1)=2k=0∑n−1T(k)+cn2两式相减,可得:
n
T
(
n
)
−
(
n
−
1
)
T
(
n
−
1
)
=
2
T
(
n
−
1
)
+
c
(
2
n
−
1
)
nT(n)-(n-1)T(n-1)=2T(n-1)+c(2n-1)
nT(n)−(n−1)T(n−1)=2T(n−1)+c(2n−1)
T
(
n
)
n
+
1
<
=
T
(
n
−
1
)
n
+
2
c
n
\frac{T(n)}{n+1}<=\frac{T(n-1)}{n}+\frac{2c}{n}
n+1T(n)<=nT(n−1)+n2c令
G
(
n
)
=
T
(
n
)
(
n
+
1
)
G(n) = \frac{T(n)}{(n+1)}
G(n)=(n+1)T(n)则有:
G
(
n
)
≤
C
(
n
−
1
)
+
2
c
n
=
G
(
n
−
2
)
+
2
c
(
1
n
−
1
+
1
n
)
=
G
(
n
−
3
)
+
2
c
(
1
n
−
2
+
1
n
−
1
+
1
n
)
=
G
(
n
−
k
)
+
2
c
(
1
n
−
k
+
1
+
.
.
.
+
1
n
−
1
+
1
n
)
G(n)≤C(n−1)+2cn=G(n−2)+2c(1n−1+1n)=G(n−3)+2c(1n−2+1n−1+1n)=G(n−k)+2c(1n−k+1+...+1n−1+1n)
所以,Quicksort 算法的平均时间复杂度为:
T
(
n
)
=
G
(
n
)
(
n
+
1
)
=
θ
(
n
l
o
g
n
)
T(n)=G(n)(n+1)=\theta(nlogn)
T(n)=G(n)(n+1)=θ(nlogn)