QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 3374|回复: 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 V9 K9 [8 a4 t4 D/ [& M5 D

1 d, f7 ^: \; l1 j1 _选择问题的一个应用就是寻找中值元素,此时k = [n / 2 ]。中值是一个很有用的统计量,例如中间工资,中间年龄,中间重量。其他k值也是有用的。例如,通过寻找第n / 4 , n / 2和3 n / 4这三个元素,可将人口划分为4份。
6 {5 e& b  J: [5 q+ b& W7 R
5 n2 \% N( J# p& B* Z9 }选择问题可在O ( n l o g n )时间内解决,方法是首先对这n个元素进行排序(如使用堆排序式或归并排序),然后取出a [ k - 1 ]中的元素。若使用快速排序(如图1 4 - 11所示),可以获得更好的平均性能,尽管该算法有一个比较差的渐近复杂性O( n2 )。  ], n$ a" u# L; F' S8 a- B

3 H, t. P+ _2 Q2 q5 I8 @$ B  _可以通过修写程序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)。* |7 W- w5 x( z0 F* a" H9 k

- O3 [+ K4 E8 o1 Z1 a程序14-7 寻找第k 个元素
, U! \0 ~2 v* e1 l; l4 B
( x! t7 S- m2 G( ?: o7 _3 H2 Ztemplate<CLASS T>+ T( x! ]7 K3 O) y
: }3 W5 O; O5 L  N+ l
T Select(T a[], int n, int k)
% Z1 v& h$ _' y% l8 Y$ o* W' ?" D1 X
6 T, _# ^" K1 \3 E1 n{// 返回a [ 0 : n - 1 ]中第k小的元素
* D8 j$ ~6 \. H+ Y2 l5 j* V
, P7 o1 b6 L% ~+ Z  U! j// 假定a[n] 是一个伪最大元素
& ]: t; `) a) M* F, F0 D. p
1 f0 B( e  h8 A7 [: j7 X% Iif (k &lt; 1 || k &gt; n) throw OutOfBounds();
' Q$ ?; l& r# Z
  E4 [( ^2 ^* S1 q& w$ b0 Zreturn select(a, 0, n-1, k);
' B& s; }" {$ I
  s" V& A, X/ C' R9 C6 \  f}
/ B; [" I  K( S, k4 d" \
/ H- y# y6 q+ m- ptemplate<CLASS T>" Y3 d7 _# b2 J1 s8 \! d

" g+ r1 w8 I$ \! C3 J/ Y" |T select(T a[], int l, int r, int k)1 v1 s! l; _8 c  |( r7 Y; x

7 V% W# U1 _; B7 A* u7 G2 a{// 在a [ l : r ]中选择第k小的元素/ m! `4 J0 C" g  j8 T( o+ K
" U, u* A4 b4 K7 t5 s
if (l &gt;= r) return a[l];
$ l' b4 v" X- a: d9 b
& R+ B) K( X3 S  v- p1 }int i = l, // 从左至右的游标
5 q# Q5 ]& ~% A$ ^- V2 x
7 h  f. {1 D" I& ~j = r + 1; // 从右到左的游标, P: l0 p$ Z. E- j/ t% N
/ Q) i: [  c9 d# {
T pivot = a[l];5 g* _! Q  O  @! P

8 R0 R  B' m8 T$ X6 h0 T// 把左侧&gt;= pivot的元素与右侧&lt;= pivot 的元素进行交换- R, @8 m9 k. S

, @6 c$ h7 T! s" {- cwhile (true) {4 f5 f0 a/ l' {# _% @

( h# b2 y  m4 D' ydo {// 在左侧寻找&gt;= pivot 的元素# d% M  l# F7 Y% @5 [& |

9 ]. K" U! g- Y/ [i = i + 1;+ ^3 K6 Q5 d$ x" ~, c
, \1 [% i3 ?9 L1 o! r% c% s
} while (a &lt; pivot);7 ~) v) r4 \. k) F  I

5 X7 v4 V" T7 U" Y9 \" O2 hdo {// 在右侧寻找&lt;= pivot 的元素
. |+ ?  P* G; s6 n! `9 U: b5 y, F5 c$ N' T- v
j = j - 1;
4 q" }; d# ?/ z4 J. Z1 F
* l" n0 R9 {. ?' c; Q0 j0 k} while (a[j] &gt; pivot);
" i& o& n" @4 [5 B/ R$ V) e% W# L6 l+ C  J- @
if (i &gt;= j) break; // 未发现交换对象, ?; S; Y" C' i+ z. K
  V2 Z" ]0 N& I( P, _) ?) B
Swap(a, a[j]);8 q" s* b& B1 x8 M7 G# f: g
. q' B. L3 C  h2 d/ r! E
}
' G' z( h. w9 u/ ~
1 w) v/ B7 z% G& d: H; n" Zif (j - l + 1 == k) return pivot;: J8 m, h4 r* ~- S6 }

/ B5 }3 F( {2 G) `( A" t// 设置p i v o t
7 k$ P: M2 f' A& Q) U* _4 g# d
' j. y9 b1 X2 o4 D, Ca[l] = a[j];& ]3 X' `0 G6 u8 }* x. G
- ~8 u8 b; w  `$ o$ G) F, D8 e3 \
a[j] = pivot;
+ B! w, A- W. {( o5 V$ N
  l2 s3 B/ Q% a' w" f// 对一个段进行递归调用: p0 T6 D- T% E: s. x/ O
7 W. S% n1 s% s, X
if (j - l + 1 &lt; k)
3 ~) ]& A- P, o, x9 X9 _& P2 j- w* l  I1 |8 Z! w, ?3 i
return select(a, j+1, r, k-j+l-1);$ G4 \; o  @! d
4 d7 W- i& {( N. ]
else return select(a, l, j-1, k);
9 ]8 b1 e9 l* ~( o8 {) {% A$ r
$ A) L+ z3 w: b$ F) y. u3 s# ]- S( H}* M2 A) g1 P2 h. d1 T  G' t

9 j- I4 Q  K  b6 w程序1 4 - 7在最坏情况下的复杂性是( n2 ),此时left 总是为空,而且第k个元素总是位于r i g h t.
  K* F# I! G- R, T- s8 }$ |- A3 D7 n& N0 g3 d1 m# H5 u2 v: ]
如果假定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 个中间元素,递归使用选择算法,求得所需要的支点元素。
& o+ s6 [; I7 x! b& E! V/ s
7 r( r$ Q* d' V# W" M5 i例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 ]。! @# J4 W( u( H

* P1 N; D8 c. V* L) q- s如果要寻找第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 )个元素。
) a* d& i8 K! J6 [8 W
- O, {' v7 V9 E$ X定理2-2 当按“中间的中间”规则选取支点元素时,以下结论为真:) O3 Q+ @4 B/ u
- v* x* i. q3 t9 y! i& }! u1 G
1) 若r=9, 那么当n≥9 0时,有m a x { |l e f e|, |r i g h t| }≤7n / 8。
9 Y2 e- M- c0 x& W
2 `* B2 V2 e- k2) 若r= 5,且a 中所有元素都不同,那么当n≥2 4时,有max{| left |, | right | }≤3n/ 4。
8 ?/ l3 z: }& Z$ N+ n, `7 j. m( J7 t, b- x7 N$ L; D
证明这个定理的证明留作练习2 3。( n0 m, |" J' m- V( G

4 z; u0 |5 [7 x+ j根据定理2 - 2和程序1 4 - 7可知,如果采用“中间的中间”规则并取r= 9,则用于寻找第k个元素的时间t (n)可按如下递归公式来计算:
+ c% x- C: }7 J# A8 R6 R/ I  w
- `$ f1 d; j5 ~. J% @在上述递归公式中,假设当n<9 0时使用复杂性为nl o gn的求解算法,当n≥9 0时,采用“中间的中间”规则进行分而治之求解。利用归纳法可以证明,当n≥1时有t (n)≤7 2cn (练习2 4 )。* N7 ~+ t5 ^/ L( l: E+ W; v! N

7 d9 _" ^+ V0 d当元素互不相同时,可以使用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 17:06 , Processed in 0.415562 second(s), 53 queries .

回顶部