QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 3371|回复: 0
打印 上一主题 下一主题

选择排序

[复制链接]
字体大小: 正常 放大
韩冰        

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

跳转到指定楼层
1#
发表于 2004-10-4 05:17 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
<>对于给定的n 个元素的数组a [ 0 : n - 1 ],要求从中找出第k小的元素。当a [ 0 : n - 1 ]被排序时,该元素就是a [ k - 1 ]。假设n = 8,每个元素有两个域k e y和I D,其中k e y是一个整数,I D是一个字符。假设这8个元素为[ ( 1 2 ,a),( 4 ,b),( 5 ,c),( 4 ,d),( 5 ,e),( 1 0 ,f),( 2 ,g),( 2 0 ,h)], 排序后得到数组[ ( 2 ,g),( 4 ,d),( 4 ,b),( 5 ,c),( 5 ,e),( 1 0 ,f),( 1 2 ,a),( 2 0 ,h) ]。如果k = 1,返回I D为g 的元素;如果k = 8,返回I D为h 的元素;如果k = 6,返回是I D为f 的元素;如果k = 2,返回I D为d 的元素。实际上,对最后一种情况,所得到的结果可能不唯一,因为排序过程中既可能将I D为d 的元素排在a [ 1 ],也可能将I D为b 的元素排在a [ 1 ],原因是它们具有相同大小的k e y,因而两个元素中的任何一个都有可能被返回。但是无论如何,如果一个元素在k = 2时被返回,另一个就必须在k = 3时被返回。9 {2 I* j, x7 X: [
7 l  t" f6 d; ]6 r. g
选择问题的一个应用就是寻找中值元素,此时k = [n / 2 ]。中值是一个很有用的统计量,例如中间工资,中间年龄,中间重量。其他k值也是有用的。例如,通过寻找第n / 4 , n / 2和3 n / 4这三个元素,可将人口划分为4份。/ F. u( I& l# z$ n- G
( A  o/ s( k  e7 h% P. i" J+ h
选择问题可在O ( n l o g n )时间内解决,方法是首先对这n个元素进行排序(如使用堆排序式或归并排序),然后取出a [ k - 1 ]中的元素。若使用快速排序(如图1 4 - 11所示),可以获得更好的平均性能,尽管该算法有一个比较差的渐近复杂性O( n2 )。& B- ]$ Z2 k5 H) h9 P! V+ X' k# O
% N  I0 s- ?% v: u. a
可以通过修写程序1 4 - 6来解决选择问题。如果在执行两个w h i l e循环后支点元素a [ l ]被交换到a [ j ] ,那么a [ l ]是a [ l : j ]中的第j - l + 1个元素。如果要寻找的第k 个元素在a [ l : r ]中,并且j - l + 1等于k,则答案就是a [ l ];如果j - l + 1 &lt; k,那么寻找的元素是r i g h t中的第k - j + l - 1个元素,否则要寻找的元素是left 中的第k个元素。因此,只需进行0次或1次递归调用。新代码见程序1 4 - 7。S e l e c t中的递归调用可用f o r或w h i l e循环来替代(练习2 5)。
6 Z* G3 T3 S% V. q( A
% E' _) Z. @/ q程序14-7 寻找第k 个元素
8 I1 ]6 d2 W9 k2 ]
# Z/ F4 r. T2 ^$ y7 Etemplate<CLASS T>/ K$ L0 r, g+ V' b8 t( f
: w) g2 f" u; A, s
T Select(T a[], int n, int k)
* x' d. h1 P1 {$ B  |: S/ p1 N  T" m! d
{// 返回a [ 0 : n - 1 ]中第k小的元素- h2 V+ _( z% @7 M+ _0 l" Y
  {( Y. N. H, ^9 H
// 假定a[n] 是一个伪最大元素
* l/ e" O, M* d0 Y9 A' l# Z( K& K* S
if (k &lt; 1 || k &gt; n) throw OutOfBounds();
& w- ?: g. h2 @2 p
' r6 D+ b6 S; x* I" c7 Y  S1 Yreturn select(a, 0, n-1, k);  m. \- {/ A9 ~1 O' s
9 }/ s( o* E, i# e3 Q5 x: S
}! S& w8 f! a/ q5 n$ X$ {) @

+ M5 ?& v# c  \$ T7 d$ k/ N  S- qtemplate<CLASS T>! p! e. L6 N# ?

" |8 k! a7 t% G2 P" M0 f( W! Z, J3 B' |T select(T a[], int l, int r, int k)2 Y4 p& g4 _! U' j/ C1 e2 u

8 e5 ], ]. O7 R. c5 Y5 G6 Q{// 在a [ l : r ]中选择第k小的元素8 b, ]! ~" _- N

  e1 V6 i0 b/ q5 F/ h8 t' eif (l &gt;= r) return a[l];
& O7 O2 ?4 E. k# Y/ R! l4 [& ~6 x1 C4 B7 d  V, M2 m8 [! H% U
int i = l, // 从左至右的游标
7 S4 h9 _2 v) \. Q# e/ x6 h
7 ^) J9 _+ ~6 g; B' F4 pj = r + 1; // 从右到左的游标" }/ w: ^- d% V+ D  f

3 F# j* a& ^2 m! i! a* wT pivot = a[l];
  E+ X9 v( e0 e$ w" \
9 k1 _. I, A5 W* W, r  V// 把左侧&gt;= pivot的元素与右侧&lt;= pivot 的元素进行交换
6 d+ x5 [5 ]3 V  c/ p% a, v9 a( D0 X+ n
while (true) {# t0 M+ F8 X$ C8 \% f9 c7 `, y
8 I+ ]% Y9 L) A# H- ?
do {// 在左侧寻找&gt;= pivot 的元素! y5 x( w. I+ J1 R3 l6 @  l
% b& _2 f3 l# ]( |
i = i + 1;: }1 N4 N) Z9 e4 j, X; s

4 I9 Q& ^' |2 k; |9 b* \} while (a &lt; pivot);9 Z, G& Z4 J3 m- [( f" c, J% ^
: H" ?; w, r7 g' q
do {// 在右侧寻找&lt;= pivot 的元素
  F* }9 h; V+ f" m/ W; n+ E7 D2 E5 B+ k# F$ Z
j = j - 1;
$ C+ y' J1 B. j& J4 s# J( d/ g+ k7 b3 P; Y  I( |
} while (a[j] &gt; pivot);" m$ b2 T. ~! i

3 r: g: |/ j+ }6 W# J. w/ ~if (i &gt;= j) break; // 未发现交换对象+ y( I1 V1 a& J# X7 J' I
9 O' M1 L$ c' n8 o) P
Swap(a, a[j]);7 u5 r5 a) a1 j% \9 t! f  h. e+ V

, o0 G  {" O" D4 _: t' Y}0 Y" I7 }) z9 @  S* }; s8 v
! ^! M2 m" M5 i- P3 C9 M* e$ g1 t
if (j - l + 1 == k) return pivot;% D& J/ ~0 @+ v# I5 i

, ?. `8 J  r- ?' }* t// 设置p i v o t' T- C: `8 f+ L% O* L4 R8 q
6 v8 M+ L6 ^) ?* U
a[l] = a[j];
( U7 U5 z3 ?% ~& d( Y, T; E1 L# v' V- \3 j$ v6 y8 {) C9 A# p0 X
a[j] = pivot;
2 i1 W, @' {# g; ]4 R8 i& m- e% |2 _& C; m* u& C, ^' D* Z* `
// 对一个段进行递归调用' `! R3 O4 _* P4 E

$ i8 d( Q9 v" N" bif (j - l + 1 &lt; k)
! R& L6 D& L$ i! Y+ o' U1 i, |! ?& w, ]: u0 z, b: R  ?
return select(a, j+1, r, k-j+l-1);! N0 j8 g. e, w: y9 F/ U8 W! @

* O4 ^3 w. O" e4 Eelse return select(a, l, j-1, k);% ]) Q" l& p9 M8 t0 A# y

: A, H% T( K' H) k, y1 v}
/ {! o; Y3 f' Q& L
# K5 e* Z" z' e6 l& B# T* K1 f/ ]程序1 4 - 7在最坏情况下的复杂性是( n2 ),此时left 总是为空,而且第k个元素总是位于r i g h t.
$ ^: A! F' E" @& @7 l
2 u1 P* F' k1 Z. e+ s如果假定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 个中间元素,递归使用选择算法,求得所需要的支点元素。1 `6 M% Z5 u5 L3 x" E' ], k
/ C+ }6 T& H: b$ V3 j
例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 ]。- z+ Y" r( A5 S/ r# Q

" W1 c" I+ o$ ~如果要寻找第k个元素且k&lt; 1 2,则仅仅需要在l e f t中寻找;如果k= 1 2,则要找的元素就是支点元素;如果k&gt; 1 2,则需要检查r i g h t中的1 5个元素。在最后一种情况下,需在r i g h t中寻找第(k- 1 2 )个元素。
# T2 ]# b& {- r0 t: X& B( W& Z
, s2 v/ d* |5 N/ O4 t( P1 R4 O! C定理2-2 当按“中间的中间”规则选取支点元素时,以下结论为真:
1 a2 z8 Q: ]7 h7 a2 s& v' }$ Y) p- }! z3 K% Q
1) 若r=9, 那么当n≥9 0时,有m a x { |l e f e|, |r i g h t| }≤7n / 8。7 P* V) Q* P( z& B0 y+ e
& K/ b5 W0 ?0 s3 g: f1 r. L
2) 若r= 5,且a 中所有元素都不同,那么当n≥2 4时,有max{| left |, | right | }≤3n/ 4。) d) c# {- `; w2 d& f

. a/ A+ f6 i7 z7 G证明这个定理的证明留作练习2 3。
, \$ @- h, {$ @! }/ \  T/ ]0 N0 s" \9 H7 z
根据定理2 - 2和程序1 4 - 7可知,如果采用“中间的中间”规则并取r= 9,则用于寻找第k个元素的时间t (n)可按如下递归公式来计算:
) J  z  `6 B5 T, n
3 I' @  k" |+ J% C- [" _" c在上述递归公式中,假设当n<9 0时使用复杂性为nl o gn的求解算法,当n≥9 0时,采用“中间的中间”规则进行分而治之求解。利用归纳法可以证明,当n≥1时有t (n)≤7 2cn (练习2 4 )。! }4 f" h2 l6 W# u4 T* G9 u

) @0 y9 K3 |+ ~7 q当元素互不相同时,可以使用r= 5来得到线性时间性能。</P>
zan
转播转播0 分享淘帖0 分享分享0 收藏收藏0 支持支持0 反对反对0 微信微信
您需要登录后才可以回帖 登录 | 注册地址

qq
收缩
  • 电话咨询

  • 04714969085
fastpost

关于我们| 联系我们| 诚征英才| 对外合作| 产品服务| QQ

手机版|Archiver| |繁體中文 手机客户端  

蒙公网安备 15010502000194号

Powered by Discuz! X2.5   © 2001-2013 数学建模网-数学中国 ( 蒙ICP备14002410号-3 蒙BBS备-0002号 )     论坛法律顾问:王兆丰

GMT+8, 2026-4-20 09:55 , Processed in 0.339172 second(s), 52 queries .

回顶部