【算法证明 三】计算顺序统计量的复杂度

计算顺序统计量,在 c++ 标准库中对应有一个函数:nth_element。其作用是求解一个数组中第 k 大的数字。常见的算法是基于 partition 的分治算法。不难证明这种算法的最坏复杂度是 Θ ( n 2 ) \Theta(n^2) Θ(n2)。但是其期望复杂度是 Θ ( n ) \Theta(n) Θ(n)

另外,存在一种最坏复杂度是 Θ ( n ) \Theta(n) Θ(n) 的算法,其设计和证明思路比较有意思,拿来说一下。

基于 partition 的算法期望复杂度证明

求期望离不开随机变量。假设在 n 个元素的数组 A [ p . . . q ] A[p...q] A[p...q] 上运行算法的时间是 T(n)。partition 算法会将 A 数组中元素等概率的选为主元并分割。定义指示器随机变量
X k = { 分割后左半边数组的元素有正好有 k 个 } X_k = \{分割后左半边数组的元素有正好有 k 个\} Xk={分割后左半边数组的元素有正好有k}
则有 E ( X k ) = 1 / n × 1 + ( n − 1 ) / n × 0 = 1 / n E(X_k)=1/n × 1 + (n - 1) / n × 0 = 1 / n E(Xk)=1/n×1+(n1)/n×0=1/n

将 A 分为两部分后,算法会选择一边进行递归。为求得最坏情况,假设每次都从较长的一边进行递归,则有不等式
T ( n ) ≤ ∑ k = 1 n X k ⋅ T ( m a x ( k − 1 , n − k ) ) + O ( n ) T(n) \le \sum_{k=1}^n X_k \cdot T(max(k-1, n - k)) + O(n) T(n)k=1nXkT(max(k1,nk))+O(n)
取期望得
E ( T ( n ) ) ≤ E ( ∑ k = 1 n X k ⋅ T ( m a x ( k − 1 , n − k ) ) ] + O ( n ) E(T(n)) \le E(\sum_{k=1}^n X_k \cdot T(max(k-1, n - k))] + O(n) E(T(n))E(k=1nXkT(max(k1,nk))]+O(n)
根据事件间独立性和线性关系,得
E ( T ( n ) ) ≤ ∑ k = 1 n E ( X k ) ⋅ E ( T ( m a x ( k − 1 , n − k ) ) ) ] + O ( n ) = 1 n ∑ k = 1 n E ( T ( m a x ( k − 1 , n − k ) ) ) ] + O ( n ) E(T(n)) \le \sum_{k=1}^n E(X_k) \cdot E(T(max(k-1, n - k)))] + O(n) \\ = \frac{1}{n} \sum_{k=1}^n E(T(max(k-1, n - k)))] + O(n) E(T(n))k=1nE(Xk)E(T(max(k1,nk)))]+O(n)=n1k=1nE(T(max(k1,nk)))]+O(n)
取较大的边进行缩放,得到
E ( T ( n ) ) ≤ 2 n ∑ k = n / 2 n E [ T ( k ) ] + O ( n ) E(T(n)) \le \frac{2}{n} \sum_{k=n/2}^n E[T(k)] + O(n) E(T(n))n2k=n/2nE[T(k)]+O(n)

用代入法来证明 E ( T ( n ) ) = O ( n ) E(T(n)) = O(n) E(T(n))=O(n),假设 E ( T ( n ) ) ≤ c n E(T(n)) \le cn E(T(n))cn,代入公式右半边,同时为方便说明,选择常数 a 代入 O(n) 中

E ( T ( n ) ) ≤ 2 n ∑ k = n / 2 n c k + a n = 2 n ⋅ 3 n / 2 × n / 2 2 + a n = 3 c n 4 + a n = ( 3 c + 4 a ) n 4 E(T(n)) \le \frac{2}{n} \sum_{k=n/2}^n ck + an \\ = \frac{2}{n} \cdot \frac{3n/2 × n/2}{2} + an\\ = \frac{3cn}{4} + an\\ =\frac{(3c + 4a)n}{4} E(T(n))n2k=n/2nck+an=n223n/2×n/2+an=43cn+an=4(3c+4a)n
只要选取较大得常数 c 即可满足 E ( T ( n ) ) ≤ c n E(T(n)) \le cn E(T(n))cn,方式如下,令
( 3 c + 4 a ) n 4 ≤ c n \frac{(3c + 4a)n}{4} \le cn 4(3c+4a)ncn
c ≥ 16 a c \ge 16a c16a
证明完毕,期望复杂度是 Θ ( n ) \Theta(n) Θ(n)

最坏情况下是线性的算法

该算法常数比较大,先描述一下基本原理
第一步,找到一个特别的中位数

  1. 将数组每 5 个元素分为一组
  2. 每组分别排序,找到 n / 5 个中位数
  3. 将这 n / 5 个中位数,递归调用本算法,找到其中位数 x
    至此找到了一个特别的中位数的中位数 x
    第二步,划分
  4. 使用 x 对数组进行划分。设 x 是第 k 小的数
  5. 如果 k = i 则结束,否则根据情况在低区或者高区来进行递归调用

证明:

首先分析这个特殊的中位数的中位数 x 的性质。可以知道,在数组中,至少有 3 n 10 − 6 \frac{3n}{10}-6 103n6个元素大于 x,同理有至少有 3 n 10 − 6 \frac{3n}{10}-6 103n6 个元素小于 x。也就是说,第5步的最坏情况,递归调用作用在 7 n 10 + 6 \frac{7n}{10}+6 107n+6个元素上。现在可以设计递推式。
步骤1 2 4 总共需要 O(n) 的复杂度,步骤 3 需要时间为 T(n / 5),步骤 5 需要时间最多为 T ( 7 n 10 + 6 ) T(\frac{7n}{10}+6) T(107n+6),因此有
T ( n ) ≤ T ( n / 5 ) + T ( 7 n / 10 + 6 ) + O ( n ) T(n) \le T(n / 5) + T(7n/10 + 6)+ O(n) T(n)T(n/5)+T(7n/10+6)+O(n)

再次使用替换法。假设 某个适当大的常数 c 满足 T ( n ) ≤ c n T(n) \le cn T(n)cn,某个常数 a 来表示 公式中 O(n) 的上界。则有
T ( n ) ≤ c n / 5 + 7 c n / 10 + 6 c + a n T(n) \le cn/5 + 7cn/10 + 6c + an\\ T(n)cn/5+7cn/10+6c+an
为挑选出足够大的 c 列出如下不等式,若如下不等式成立,则找到了足够大的 c
c n / 5 + 7 c n / 10 + 6 c + a n ≤ c n − n c / 10 + 6 c + a n ≤ 0 cn/5 + 7cn/10 + 6c + an \le cn\\ -nc/10 + 6c+an\le0 cn/5+7cn/10+6c+ancnnc/10+6c+an0
n > 60 n \gt 60 n>60时有如下变换
c ≥ 10 a n / ( n − 60 ) c \ge 10an/(n-60) c10an/(n60)
函数图像大致如下
在这里插入图片描述因此 不妨设 n ≥ 120 n \ge 120 n120 , 有 n / ( n − 60 ) < 2 n/(n - 60) < 2 n/(n60)<2,即
c ≥ 20 a , n ≥ 120 c \ge 20a, n \ge120 c20a,n120

结果合并如下
T ( n ) ≤ { O ( 1 ) , n < 120 O ( n ) , n ≥ 120 T(n) \le \begin{cases} O(1), n < 120 \\ O(n), n \ge 120 \end{cases} T(n){O(1),n<120O(n),n120

证毕

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值