QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 3474|回复: 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时被返回。/ ]3 z0 r8 x8 z# d1 K7 B& k% _
* P- Q: T1 q2 a8 M4 ?
选择问题的一个应用就是寻找中值元素,此时k = [n / 2 ]。中值是一个很有用的统计量,例如中间工资,中间年龄,中间重量。其他k值也是有用的。例如,通过寻找第n / 4 , n / 2和3 n / 4这三个元素,可将人口划分为4份。
8 W, B0 u$ y- y. r. J7 U8 W$ U  M) g/ k4 V5 a
选择问题可在O ( n l o g n )时间内解决,方法是首先对这n个元素进行排序(如使用堆排序式或归并排序),然后取出a [ k - 1 ]中的元素。若使用快速排序(如图1 4 - 11所示),可以获得更好的平均性能,尽管该算法有一个比较差的渐近复杂性O( n2 )。
9 i+ j! Q4 N- ?( _
4 [) T2 i) s% ~0 y! J* T可以通过修写程序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)。
4 Y, J- x$ F  a  l/ C6 u1 |6 L' G2 J2 t
程序14-7 寻找第k 个元素
; F5 \8 e4 w& G! w0 U0 x1 N8 r9 x7 }1 e: I
template<CLASS T>2 G' z$ k6 \: ]5 W9 e' w* O

$ h5 ~3 N1 X9 |9 s, K  ?T Select(T a[], int n, int k)' X! j* G+ w4 s& d2 z' ?5 f# ?0 h

) o  {7 q9 T: D/ ^% Z{// 返回a [ 0 : n - 1 ]中第k小的元素1 |( }! g9 }8 `* s- Q) `. p

" X' n; X1 h: U) ]  f+ L  ^; K2 d. `// 假定a[n] 是一个伪最大元素
3 B0 e; G+ Q1 k* j' w
/ o/ y# j. D0 }5 K1 j2 u3 kif (k &lt; 1 || k &gt; n) throw OutOfBounds();
! @% `8 U2 ]/ X! ~0 p
1 p' I7 m# e6 zreturn select(a, 0, n-1, k);
7 S9 Z& E9 G1 X) V% {! L
$ R1 p8 I  j( O" g}
) o- f& }+ V0 E- P$ n, Q! z" l+ r" R
5 d2 x. @! r* p, J) atemplate<CLASS T>- D/ F% h5 B  w- A
0 l$ A1 m, V0 N# G5 ^8 j8 W
T select(T a[], int l, int r, int k)
( r) E6 W* C$ j+ i- w+ z$ H1 _# R( n! y9 B5 e. Z3 H0 j, I$ l
{// 在a [ l : r ]中选择第k小的元素1 P, y3 ^+ ~( G0 J3 a4 X

$ j1 `; ^( v+ ?( p4 P4 j, kif (l &gt;= r) return a[l];
7 O) |# N* w0 o0 t% I& @9 u% Y6 f- `/ Y. l# x$ |
int i = l, // 从左至右的游标! Q+ H! F9 \. `

: C; \+ ^/ \' S9 K8 g9 Aj = r + 1; // 从右到左的游标! ~! B2 ^: U$ e0 [  \7 d
3 N9 I! _! s+ ?) q, [
T pivot = a[l];
! v4 ~3 C- ^" H7 {" @) o3 ], v( P! n; c5 G9 q% X8 d
// 把左侧&gt;= pivot的元素与右侧&lt;= pivot 的元素进行交换
! x' a$ k! u) |# q5 u
4 @! d5 |" A9 k& a; \% iwhile (true) {% y# E6 R5 J1 o9 E

4 }. R( }+ N; o/ ?! }' ?# @do {// 在左侧寻找&gt;= pivot 的元素  Z! w* q9 U/ A
) z  x9 R. \9 o/ e% Q
i = i + 1;2 b5 q' |+ ~6 c, d0 E, E

$ n3 |+ A& R/ P+ ~& s} while (a &lt; pivot);
3 Q, {0 k/ _: r$ D) d8 B" \- V- E, p, E3 F& L6 l& I2 b
do {// 在右侧寻找&lt;= pivot 的元素
8 Z1 k" B% x. g8 [" d# S  ~! [3 B& T8 w4 i& n
j = j - 1;
2 r* F) ^. @' |+ D3 R
7 i$ Y) k. T7 V& E; W: _  Y} while (a[j] &gt; pivot);
: p  Y- U  T& C5 Y5 q! u2 G7 L8 O9 w$ V4 r3 K$ C, F
if (i &gt;= j) break; // 未发现交换对象& {2 v+ M  J: V, F
. B% n* G% n% n% j' K
Swap(a, a[j]);
/ b: S3 O" E+ K: g, t0 s7 V
; j+ v/ J/ Q3 }/ m, t}0 K! M) Y+ B: k
# e% R0 C! Y$ ?) c" ~; W- P
if (j - l + 1 == k) return pivot;
4 i% f- F2 V9 y' V$ D
5 ?0 f7 u7 f0 `4 A// 设置p i v o t! N- H6 F( ]5 q
& ]. s# k9 }9 M0 m$ M2 r, e
a[l] = a[j];5 {& X0 i7 W; \6 ]5 r
0 b- O9 H4 O& p
a[j] = pivot;( q  @* k: _' y$ L9 d

4 Q- ~( f5 o6 U  o) T8 L// 对一个段进行递归调用
! @) }) f2 p* f- D5 g; @2 c3 \9 u( {, U) }' V: L! S( R
if (j - l + 1 &lt; k)! ?# d: K( U+ a  ~8 p$ j3 Y7 ^
4 A2 U( d% _4 @( A! e$ K( O, K
return select(a, j+1, r, k-j+l-1);
8 c; G6 I+ G' N- K/ l- V
' Q+ P$ o+ |: q4 F' W6 i5 Lelse return select(a, l, j-1, k);# [1 \& f7 C4 b- \$ t* t

+ p1 h! L0 ]/ ?5 a3 e}
% M  o1 H0 u, k8 D& Q) i' z0 p
* j$ B" C2 s- P6 b; ]程序1 4 - 7在最坏情况下的复杂性是( n2 ),此时left 总是为空,而且第k个元素总是位于r i g h t.+ A6 ?( h( ]! h5 J2 Z& j7 v) s
$ X, C  F, y; D& }  w
如果假定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 个中间元素,递归使用选择算法,求得所需要的支点元素。
/ R. ]- m5 K7 Z6 J1 X1 }; z, Y2 G2 T+ y0 r) A7 \6 {& g
例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 ]。
7 _; }; h+ j8 |* L8 F6 G3 |2 k2 ?6 I6 M  s3 Z
如果要寻找第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 )个元素。! L$ Q5 X" X+ o6 @% s
  b# Z) B9 [, r  w7 W
定理2-2 当按“中间的中间”规则选取支点元素时,以下结论为真:0 A; s# |& d3 L* U6 |6 c3 n; @! V

& [3 u; `% E1 `1 M  J1) 若r=9, 那么当n≥9 0时,有m a x { |l e f e|, |r i g h t| }≤7n / 8。
+ F4 `7 ^5 w# m' I6 i& l8 l% J2 }. W+ W: y
2) 若r= 5,且a 中所有元素都不同,那么当n≥2 4时,有max{| left |, | right | }≤3n/ 4。
' E2 g5 M7 }2 w% w) M
/ P1 {- N4 X" e0 @% u0 ]证明这个定理的证明留作练习2 3。0 f4 Z0 C" U" a* {$ Z
' U( N& ]) w% r& M
根据定理2 - 2和程序1 4 - 7可知,如果采用“中间的中间”规则并取r= 9,则用于寻找第k个元素的时间t (n)可按如下递归公式来计算:$ u! i5 G: c" j& u. `
7 N+ P2 e. M( h* z
在上述递归公式中,假设当n<9 0时使用复杂性为nl o gn的求解算法,当n≥9 0时,采用“中间的中间”规则进行分而治之求解。利用归纳法可以证明,当n≥1时有t (n)≤7 2cn (练习2 4 )。
2 l7 x, G  Z/ B. H+ S( ^
3 z6 p- F- i( }# g7 n2 b$ Z当元素互不相同时,可以使用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-10-29 02:53 , Processed in 0.579544 second(s), 51 queries .

回顶部