快轉到主要內容
  1. 博客/

快速排序中随机性的分析

·475 字·3 分鐘
Algorithms Quicksort Randomized Algorithms
汤振中
作者
汤振中
码农自学成才
目錄
Randomized Algorithms - 本文屬於一個選集。
§ 1: 本文

本文默认你已经了解基础快速排序算法、BigO记号,以及如何读懂概率与期望推导。如果这些概念不熟,先复习一下确定性快速排序和期望值的基础,会更容易理解下面的证明。

算法
#

随机化快速排序就是在每次子数组中均匀随机选择pivot的快速排序。随机性可以显式实现(随机选一个索引),也可以隐式实现(先打乱数组,再用首元素做pivot)。两种方式的算法结构一致。

R-QUICKSORT(A):
  if |A| <= 1: return A
  choose pivot p uniformly at random from A
  partition A into L = {x < p}, E = {x = p}, G = {x > p}
  return R-QUICKSORT(L) + E + R-QUICKSORT(G)

我们只需分析比较次数,排序算法的比较次数决定了时间复杂度。最坏情况是 \( O(n^2) \),但随机化使期望为 \( O(n \log n) \),而最坏情形的概率指数级降低。

复杂度分析
#

假设有个数组,按排序顺序记为 \( z_1 < z_2 < \dots < z_n \)。令 \( X_{ij} \) 为指示变量,表示 \( z_i \) 与 \( z_j \) 是否被比较过(\( i < j \))。

比较次数总和为

$$ C = \sum_{1 \le i < j \le n} X_{ij}. $$

由期望的线性性,

$$ \mathbb{E}[C] = \sum_{1 \le i < j \le n} \mathbb{E}[X_{ij}] = \sum_{1 \le i < j \le n} \Pr[X_{ij} = 1]. $$

声明: \( z_i \) 与 \( z_j \) 被比较,当且仅当集合 \( {z_i, z_{i+1}, \dots, z_j} \) 中第一次被选为pivot的是 \( z_i \) 或 \( z_j \)。

证明: 考察该连续区间内第一个被选中的pivot。如果pivot是 \( z_k \), \( i < k < j \),那么 \( z_i \) 与 \( z_j \) 会被分到不同分区,之后不再相见。若第一个pivot是 \( z_i \)(或 \( z_j \)),在那次划分中 \( z_i \)(或 \( z_j \))会与区间内所有元素比较。证毕。

pivot在区间中均匀随机选取,因此

$$ \Pr[X_{ij} = 1] = \frac{2}{j - i + 1}. $$

于是

$$ \mathbb{E}[C] = \sum_{1 \le i < j \le n} \frac{2}{j - i + 1}. $$

令 \( k = j - i + 1 \),带入化简,

$$ \mathbb{E}[C] = \sum_{k=2}^{n} (n - k + 1) \cdot \frac{2}{k} = 2 \sum_{k=2}^{n} \frac{n - k + 1}{k}. $$

利用调和数 \( \sum_{k=1}^{n} \frac{1}{k} = H_n \),得到期望时间复杂度

$$ \mathbb{E}[C] = 2(n+1)H_n - 4n = O(n \log n). $$

最坏情况的概率?
#

\( O(n^2) \) 的行为只会在每次pivot都是子数组中的极值(最小或最大)时发生。整个过程的概率为

$$ \Pr[\text{最坏情况}] = \prod_{k=2}^{n} \frac{2}{k} = \frac{2^{n-1}}{n!}, $$

这不能再小了吧。当 \( n = 10 \) 时约为 \( 2^9/10! \approx 0.0141\% \),当 \( n = 20 \) 时约为 \( 2^{19}/20! \approx 0.0000000000216\% \)。 虽然算法仍保留最坏情况上界,但随机选pivot这个操作把最坏情况变成极端小概率事件。

绝大部分时候都是 \(O(n \log n)\)?
#

一个pivot,如果它将子问题规模控制在当前规模的 \( 3/4 \) 以内,我们称之为pivot。经过 \( t \) 次好pivot后,子问题规模至多为 \( (3/4)^t n \)。要使其 \( \le 1 \),即递归结束,需要 \( t \ge c \log n \)(\( c \) 为常数)。

每次pivot为好的概率至少是 \( 1/2 \)(只要落在中间1/4至3/4这一半即可)。考虑某个子问题,在其 \( m \) 次pivot选择中,令 \( G \) 为好pivot的个数。虽然这些事件不独立,但每次pivot在条件概率下至少为好pivot的概率仍是 1/2,因此 \( G \) 类似于 \( \text{Binomial}(m, 1/2) \) 的随机变量。

不失一般性,取 \( m = \frac{2c}{1 - \delta} \log n \),其中 \( \delta \in (0,1) \)。则均值为 \( \mu = m/2 = \frac{c}{1 - \delta} \log n \),坏事件(进展不足)为 \( G < c \log n = (1 - \delta)\mu \)。对二项分布应用 Chernoff bound,

$$ \Pr[G < (1 - \delta)\mu] \le \exp\left(-\frac{\delta^2 \mu}{2}\right). $$

因此

$$ \Pr[G < c \log n] \le \exp\left(-\frac{\delta^2 \mu}{2}\right) = n^{-\frac{\delta^2}{2(1 - \delta)}c}. $$

对单个元素而言,它经历超过 \(c \log n\) 次递归的概率是多项式级别的小。再对所有 \( n \) 个元素做并集界,有

$$ \Pr[\text{任何子问题耗时过长}] \le O(n) \cdot n^{-2} = O(n^{-1}), $$

当 \( n \to \infty \) 时趋于 0。直观上讲,这和连续抛硬币类似。例如 40 次抛掷的期望是 20 次正面,而出现少于 10 次正面的概率只有约 0.03%。随着 \( n \) 的增大,偏离期望稍微大一点的事件,发生的可能性都极小。 同理,随机化快速排序在 \( \Theta(\log n) \) 步之后仍未取得足够进展的概率以多项式速度衰减,且指数随 \( c \) 线性增长。

总结
#

随机化在不改变算法结构的情况下,让快速排序在期望下是永远高效的。时间复杂度为 \( O(n \log n) \) ,同时递归深度显著超出 \( \Theta(\log n) \) 的概率极小。

参考文献
#

  • Motwani, Raghavan. Randomized Algorithms, Chapter 1, Introduction.
Randomized Algorithms - 本文屬於一個選集。
§ 1: 本文

相關文章

本想电影感,却偏偏翻了车
Film Kodak 5219 Kodak 5207 Kentmere Pan 200 Pentax 17 Nikon Fe
静止了,所有的花开
Cat Flower Spring Film Portra 400 Fujifilm 400 Fujifilm 200 Pentax 17 Nikon Fe
富士400——等到放晴那天,也许我会比较好一点
Film Fujifilm 400 Pentax 17 Nikon Fe