; d+ d S) w: z3 |, pj = r + 1; // 从右到左的游标 6 f7 `# y$ N4 s* X' p9 L " y+ Q |: u8 ^) l) o3 zT pivot = a[l]; + w' P$ a; x4 \$ z% O3 V6 W: b s" Q4 d
// 把左侧>= pivot的元素与右侧<= pivot 的元素进行交换 1 B7 ?' }' H, v6 O* C$ E+ v& J 8 B/ L$ } y$ D/ u7 g% B& Ywhile (true) {) K+ k2 d) U8 U, l
) x' ?( A1 J$ W3 X5 A6 s
do {// 在左侧寻找>= pivot 的元素 , V# T3 O! O$ c0 C. }4 u3 I b, [7 ?( D3 r
i = i + 1;: V* D8 _# h2 N5 l, _( b
7 E* c# R8 }% x, M) B
} while (a < pivot); / o) H H! o7 ^( R: q( r 9 l; y0 W2 c7 w. Z3 Kdo {// 在右侧寻找<= pivot 的元素3 n. x. E% d0 ~
; X) m) N6 l2 y0 N. x
j = j - 1;, u/ S8 R! F2 Y) k3 t3 f O
, w6 f' R! ^/ \
} while (a[j] > pivot);, `8 \( V( e" C
+ j. h K- J/ Q N# m; d
if (i >= j) break; // 未发现交换对象 ! P% G) @" G7 N1 ?+ y/ ?4 ^ J3 u% ~* S: g g# l* I+ s; PSwap(a, a[j]);# W( u# ^3 G* l
9 S; w9 r# V4 K8 b* k! g' O} 9 Q7 Q9 n {) b# G5 J- ]6 `4 b % C+ G7 F" Z# x7 V4 {1 yif (j - l + 1 == k) return pivot;, p' {+ m9 v8 E Q/ `/ D2 H
& X8 Z$ L# }. [+ C0 ]3 ^! T// 设置p i v o t 8 K. [' @6 w8 P( J) c$ b8 `) m9 ]4 S+ M' p
a[l] = a[j]; / O2 w0 ^, `3 K& r t, Z( M6 q( G: U$ m: J- S. h
a[j] = pivot; . q4 ~, L1 h( G* L. n; T7 i $ q' l+ c5 J) T+ O3 _// 对一个段进行递归调用3 G0 H3 W' j& H1 {. M
) K/ \; w- V. Uif (j - l + 1 < k) " V+ `" Q! a- F: q3 @ 9 y5 d2 h2 v+ P6 J9 Nreturn select(a, j+1, r, k-j+l-1);) o4 y% g. G M) Z1 O
z4 t% y" u0 j6 x
else return select(a, l, j-1, k); - m* N# v0 d# X4 M; V7 z# n- i 4 ^0 v! `0 z% W1 X% o}% i8 B8 h2 |, w( [7 D0 @4 O
8 R2 }$ F6 C" [程序1 4 - 7在最坏情况下的复杂性是( n2 ),此时left 总是为空,而且第k个元素总是位于r i g h t.0 S7 Q6 C4 n T: t+ |
7 X! x0 [) @5 z1 R如果假定n 是2的幂,则可以取消公式(2 - 1 0)中的向下取整操作符。通过使用迭代方法,可以得到t (n) = (n)。若仔细地选择支点元素,则最坏情况下的时间开销也可以变成(n)。一种选择支点元素的方法是使用“中间的中间( m e d i a n - o f - m e d i a n)”规则,该规则首先将数组a中的n 个元素分成n/r 组,r 为某一整常数,除了最后一组外,每组都有r 个元素。然后通过在每组中对r 个元素进行排序来寻找每组中位于中间位置的元素。最后根据所得到的n/r 个中间元素,递归使用选择算法,求得所需要的支点元素。+ I2 J8 W3 G5 U( M* n. t2 {6 t
2 z& y, i1 s* j: R6 ?" E如果要寻找第k个元素且k< 1 2,则仅仅需要在l e f t中寻找;如果k= 1 2,则要找的元素就是支点元素;如果k> 1 2,则需要检查r i g h t中的1 5个元素。在最后一种情况下,需在r i g h t中寻找第(k- 1 2 )个元素。 ) F. n# q/ }( ~' g. G! {4 B3 a# a6 |9 j: P6 }
定理2-2 当按“中间的中间”规则选取支点元素时,以下结论为真: ) i5 O& X* J9 x3 {6 I, N9 p 0 M/ y; p" \% t3 {! U1) 若r=9, 那么当n≥9 0时,有m a x { |l e f e|, |r i g h t| }≤7n / 8。$ _2 Q* S8 L0 n! X
, r r z w r& m2) 若r= 5,且a 中所有元素都不同,那么当n≥2 4时,有max{| left |, | right | }≤3n/ 4。 - A& r+ d7 w% ^. B2 |% x7 x3 M* q8 x9 {! j" O# c
证明这个定理的证明留作练习2 3。 & w( T. X( V* a. C4 K! ?# r8 A0 E5 C: d
根据定理2 - 2和程序1 4 - 7可知,如果采用“中间的中间”规则并取r= 9,则用于寻找第k个元素的时间t (n)可按如下递归公式来计算: % S( B. t2 s# n9 L9 N" T8 F% x1 {# M+ k; O% ^3 s
在上述递归公式中,假设当n<9 0时使用复杂性为nl o gn的求解算法,当n≥9 0时,采用“中间的中间”规则进行分而治之求解。利用归纳法可以证明,当n≥1时有t (n)≤7 2cn (练习2 4 )。& p: r, B9 M/ h v/ r
" K- _# L1 U+ Z( M, M% p
当元素互不相同时,可以使用r= 5来得到线性时间性能。</P>