' V0 H. U: }" ~, m& Wwhile (true) {" G( G6 Z; y! n
2 v. Q# o+ s7 J8 ?- ]do {// 在左侧寻找>= pivot 的元素0 V/ p9 \ O2 Z& c
N! ~* K2 ^4 V" |; l
i = i + 1; x, K" x4 f; {( e & U) j- g R8 d' `. j} while (a < pivot); , k' H# |9 x* K4 y$ Q7 I/ a! D6 `2 @& q
do {// 在右侧寻找<= pivot 的元素/ c; B( p+ ~' z4 m+ h8 j7 s, V/ u
s3 x! d, H4 [
j = j - 1; 0 C! j, @# |' B- N 8 `8 V# h* L4 f! V) w} while (a[j] > pivot);$ f9 h! ?: d$ c# l' i
0 w# h _, o0 a" \$ U- j( X( H: h
if (i >= j) break; // 未发现交换对象9 Y i8 h6 ^* c- S
: E% S4 `4 j; HSwap(a, a[j]); 8 Z. _- V6 @$ m: p' T+ Q* ^5 g. L. L W7 J# S" }, j- j, m- l
} ' R& {4 [, d6 l+ `, U5 }8 B1 x W7 @0 K. G0 X$ `) I( ?% C
if (j - l + 1 == k) return pivot;( B3 I( v/ A8 B" F
7 {$ [3 H+ y/ @/ S. ^// 设置p i v o t( x. J# l, d v6 Z$ k# h6 t
8 D" n, q; x. ~+ J0 e# A N Ua[l] = a[j];3 d2 @4 s# _6 U4 ^# N
$ v1 z% s$ `2 S* Oa[j] = pivot; ' w( j" I! o2 Q8 C3 T |* \8 c4 [& q: o; C+ B' ?. b
// 对一个段进行递归调用 6 R, u" v# a/ }( b1 y 9 l* c) C6 S8 Y0 G) Iif (j - l + 1 < k) " Z" U% e0 j8 r x! Y. i: o5 R6 X1 p8 |+ M2 O/ z* H: _' ~. k
return select(a, j+1, r, k-j+l-1); 4 U7 M' _. W. o8 k u4 Q) E3 T& h
else return select(a, l, j-1, k); ) ^; O( ^5 C$ Q9 Q0 i5 u2 ]* |7 B" g: D x" o
}% Q) G! {% d, F# p# [
4 B" u- y6 r" j' J程序1 4 - 7在最坏情况下的复杂性是( n2 ),此时left 总是为空,而且第k个元素总是位于r i g h t." Q5 F7 S( b$ } }% k, d& W `
; W: e y Q( |+ T
如果假定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 个中间元素,递归使用选择算法,求得所需要的支点元素。 % p8 ]* [; n/ F6 M1 o: ^ & Y+ m7 S% z# J5 h% }例2-6 [中间的中间] 考察如下情形:r=5, n=27, 并且a= [ 2,6,8,1,4,1 0,2 0,6,2 2,11,9,8,4,3,7,8,1 6,11,1 0,8,2,1 4,1 5,1,1 2,5,4 ]。这2 7个元素可以被分为6组[ 2 , 6 , 8 , 1 , 4 ],[ 1 0 , 2 0 , 6 , 2 2 , 11 ],[ 9 , 8 , 4 , 3 , 7 ],[ 8 , 1 6 , 11 , 1 0 , 8 ],[ 2 , 1 4 , 1 5 , 1 , 1 2 ]和[ 5 , 4 ],每组的中间元素分别为4 , 11 , 7 , 1 0 , 1 2和4。[ 4 , 11 , 7 , 1 0 , 1 2 , 4 ]的中间元素为7。这个中间元素7被取为支点元素。由此可以得到l e ft= [ 2 , 6 , 1 , 4 , 6 , 4 , 3 , 2 , 1 , 5 , 4 ],m i d d l e= [ 7 ] ,r i g h t= [ 8 , 1 0 , 2 0 , 2 2 , 11 , 9 , 8 , 8 , 1 6 , 11 , 1 0 , 8 , 1 4 , 1 5 , 1 2 ]。1 d' ^! }) @/ X1 Q, E& _/ F$ |' E
& l% }; T! Q# z7 b d, o% Y如果要寻找第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 )个元素。: K8 k9 J7 ^* v0 V* L9 E5 X/ x: ?& _' D2 a
8 \0 o- U' m& z7 [$ c) e定理2-2 当按“中间的中间”规则选取支点元素时,以下结论为真:2 Z6 s5 @' s) U! D* ]! d* n, w. O
1 P5 Y$ _, s, w1) 若r=9, 那么当n≥9 0时,有m a x { |l e f e|, |r i g h t| }≤7n / 8。 7 {; O+ c+ }. J h8 i( S6 I 1 d- g9 i" n; E9 \ a2) 若r= 5,且a 中所有元素都不同,那么当n≥2 4时,有max{| left |, | right | }≤3n/ 4。5 N: x' }9 V0 h7 Q" H
$ r& t8 B. p/ O3 S! | }0 c
证明这个定理的证明留作练习2 3。& P/ J8 y. h% q; C; g. c$ a
+ {4 e# H) {) z+ T) i
根据定理2 - 2和程序1 4 - 7可知,如果采用“中间的中间”规则并取r= 9,则用于寻找第k个元素的时间t (n)可按如下递归公式来计算: % r, U- n2 e- f% J! [ * g% N; p+ }8 z9 L在上述递归公式中,假设当n<9 0时使用复杂性为nl o gn的求解算法,当n≥9 0时,采用“中间的中间”规则进行分而治之求解。利用归纳法可以证明,当n≥1时有t (n)≤7 2cn (练习2 4 )。* @/ k) W( _8 N& O+ q/ p6 z
5 r$ q) d) o4 ^
当元素互不相同时,可以使用r= 5来得到线性时间性能。</P>