• 【算法证明 二】快速排序的时间复杂度分析


    快速排序是一种分治算法。选取主元后,将数组使用 partition 算法根据主元分割成两半,再对两半分别进行排序。假设左半边数量为 q q q,则右半边数量为 n − q − 1 n-q-1 nq1。则由如下递归式,得到如下运行时间递归式:
    T ( n ) = T ( q ) + T ( n − q − 1 ) + Θ ( n ) T(n)=T(q)+T(n-q-1) + \Theta(n) T(n)=T(q)+T(nq1)+Θ(n)

    最坏时间复杂度

    最坏情况下的复杂度显然是
    T ( n ) = max ⁡ 0 ≤ q ≤ n − 1 ( T ( q ) + T ( n − q − 1 ) ) + Θ ( n ) T(n)=\max_{0\le q\le n-1}(T(q)+T(n-q-1)) + \Theta(n) T(n)=0qn1max(T(q)+T(nq1))+Θ(n)

    这里使用代入法(数学归纳法)证明:假设 T ( n ) ≤ c n 2 T(n) \le cn^2 T(n)cn2 成立,代入等式右侧,原式有
    T ( n ) ≤ c ⋅ max ⁡ 0 ≤ q ≤ n − 1 ( q 2 + ( n − q − 1 ) 2 ) + Θ ( n ) T(n) \le c\cdot \max_{0\le q\le n-1}(q^2+(n-q-1)^2) + \Theta(n) T(n)c0qn1max(q2+(nq1)2)+Θ(n)
    容易得到, q 2 + ( n − q − 1 ) 2 q^2+(n-q-1)^2 q2+(nq1)2 在端点取得最大值。因此: q 2 + ( n − q − 1 ) 2 ≤ ( n − 1 ) 2 = n 2 − 2 n + 1 q^2+(n-q-1)^2\le(n-1)^2=n^2-2n+1 q2+(nq1)2(n1)2=n22n+1,即

    T ( n ) ≤ c ( n 2 − 2 n + 1 ) + Θ ( n ) ≤ c n 2 T(n) \le c(n^2-2n+1) + \Theta(n)\le cn^2 T(n)c(n22n+1)+Θ(n)cn2
    得到上界为 O ( n 2 ) O(n^2) O(n2)
    同理,假设 T ( n ) ≥ c n 2 T(n) \ge cn^2 T(n)cn2,使用数学归纳法也可以证明 T ( n ) = Ω ( n 2 ) T(n)=\Omega(n^2) T(n)=Ω(n2),因此最坏时间复杂度是 Θ ( n 2 ) \Theta(n^2) Θ(n2)

    期望时间复杂度

    通过分析算法代码,可以知道,快速排序的操作主要为

    1. partition 操作数量
    2. partition 内部循环

    对于1,易得其 ≤ n \le n n。对于 2,主要看其内部循环中的比较数量 X X X。因此,算法的时间可以表示为 O ( n + X ) O(n+X) O(n+X)。其中 n n n 在这里不重要,凑数用的。
    如何计算快排的平均比较次数,即 E ( X ) E(X) E(X)?
    X i j X_{ij} Xij i i i j j j 是否进行了比较,比较为 1, 没比较为 0 。因为在快速排序中,两个元素之间最多比较一次(因为元素只与主元比较,而主元不参与后序的递归过程)。因此, X = ∑ i = 1 n − 1 ∑ j = i + 1 n X i j X= \sum_ {i=1} ^{n-1} \sum_{j=i+1}^n X_{ij} X=i=1n1j=i+1nXij
    对其取期望,得
    E ( X ) = ∑ i = 1 n − 1 ∑ j = i + 1 n E ( X i j ) = ∑ i = 1 n − 1 ∑ j = i + 1 n P i j , P i j 表示 i j 发生比较的概率 E(X)= \sum_ {i=1} ^{n-1} \sum_{j=i+1}^n E(X_{ij})= \sum_ {i=1} ^{n-1} \sum_{j=i+1}^n P_{ij}, P_{ij} 表示 i j 发生比较的概率 E(X)=i=1n1j=i+1nE(Xij)=i=1n1j=i+1nPij,Pij表示ij发生比较的概率

    为方便叙述,设 Z Z Z 为原数组集合的重命名, Z = { z 1 , z 2 , . . . , z n } Z= \{z_1, z_2, ... , z_n\} Z={z1,z2,...,zn},其中 z i z_i zi 表示数组中第 i i i 大值( Z Z Z 就是原数组排序后重命名一下)。
    如何求 i j i j ij 发生比较的概率 P i j P_{ij} Pij 呢?从反向入手,什么时候 z i z j z_iz_j zizj 不会发生比较呢?显然当 z i z j z_iz_j zizj 之间的某一个 z x z_x zx 先被选为主元之后, z i z j z_iz_j zizj 被分开了,所以后序的排序过程也一定不会发生比较。如果 z i z_i zi 或者 z j z_j zj 先被选为元素呢?那么 z i z j z_iz_j zizj 会发生比较。如果在 [ z i , z j ] [z_i,z_j] [zi,zj] 以外的元素被选为主元呢?这并不重要。我们只关心 [ z i , z j ] [z_i, z_j] [zi,zj] 中的数,谁先被选为主元。

    因此, P i j P_{ij} Pij 的计算大大致就清楚了,其等于 [ z i , z j ] [z_i, z_j] [zi,zj] 中, i , j i, j i,j 先被选为主元的概率,即
    P i j = 1 j − i + 1 + 1 j − i + 1 = 2 j − i + 1 P_{ij}=\frac{1}{j-i+1}+\frac{1}{j-i+1} = \frac{2}{j-i+1} Pij=ji+11+ji+11=ji+12

    代入原公式得
    E ( X ) = = ∑ i = 1 n − 1 ∑ j = i + 1 n 2 j − i + 1 E(X)== \sum_ {i=1} ^{n-1} \sum_{j=i+1}^n \frac{2}{j-i+1} E(X)==i=1n1j=i+1nji+12

    j − i j-i ji 代换为 k k k
    E ( X ) = ∑ i = 1 n − 1 ∑ k = 1 n − i 2 k + 1 < ∑ i = 1 n − 1 ∑ k = 1 n − i 2 k = ∑ i = 1 n − 1 O ( l g n ) = O ( n l g n ) E(X)= \sum_ {i=1} ^{n-1} \sum_{k=1}^{n-i} \frac{2}{k+1}<\sum_ {i=1} ^{n-1} \sum_{k=1}^{n-i} \frac{2}{k}=\sum_ {i=1} ^{n-1}O(lgn)=O(nlgn) E(X)=i=1n1k=1nik+12<i=1n1k=1nik2=i=1n1O(lgn)=O(nlgn)

    再基于比较排序的下界,可知,快速排序的期望复杂度是 Θ ( n l g n ) \Theta(nlgn) Θ(nlgn)

    证明完毕。

  • 相关阅读:
    Ubuntu22.10安装Docker运行SRS流媒体服务
    InputMan12.0J、VB.net、imTime
    Graalvm安装配置与springboot3.0尝鲜
    boa交叉编译(移植到arm)
    SpringCloud学习笔记(五) Ribbon 负载均衡服务调用
    为啥$p(w|D)=p(y|X,w)$?
    Panda3d如何获取到可用的模型?Maya、3D Max、OBJ等3D格式转换为egg、gltf文件
    c++类对象的初始化笔记(1)
    Scala 运算符
    uni-app:实现view元素强制换行(解决长字符和英文字符不换行问题)
  • 原文地址:https://blog.csdn.net/weixin_43233774/article/details/130858163