QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 3396|回复: 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时被返回。
% R7 u3 ^; ]7 a/ @' w6 `
/ q/ p$ C& g+ W: w选择问题的一个应用就是寻找中值元素,此时k = [n / 2 ]。中值是一个很有用的统计量,例如中间工资,中间年龄,中间重量。其他k值也是有用的。例如,通过寻找第n / 4 , n / 2和3 n / 4这三个元素,可将人口划分为4份。
5 |4 I4 H% x3 V+ C
8 q( T* }2 Y/ y' L- K  G选择问题可在O ( n l o g n )时间内解决,方法是首先对这n个元素进行排序(如使用堆排序式或归并排序),然后取出a [ k - 1 ]中的元素。若使用快速排序(如图1 4 - 11所示),可以获得更好的平均性能,尽管该算法有一个比较差的渐近复杂性O( n2 )。
& O( |+ \' s8 B  _6 l) L* Q9 ]. p- E2 ~3 ^
可以通过修写程序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)。
; Y2 q8 ]* B1 m; B) L, Z5 G: B2 S; O! i2 y' y
程序14-7 寻找第k 个元素( C) r* {1 h8 A3 X

* u6 s8 e2 \2 k4 h: Y+ ctemplate<CLASS T>
& f) w1 i  }9 I4 T
4 j" h- J* u& l) N# c9 _) r8 qT Select(T a[], int n, int k)! {- N/ Q/ {1 s! u8 y8 e

3 D2 {- M" S* ^$ @{// 返回a [ 0 : n - 1 ]中第k小的元素
4 C- v/ G1 S9 X! D7 F+ @, `
% F, x2 _8 D7 A( ?; @' E" Q// 假定a[n] 是一个伪最大元素
; \" i2 ]4 [, |( R0 I& M0 J! E1 }' C, t1 d. g" O0 r6 T
if (k &lt; 1 || k &gt; n) throw OutOfBounds();2 H/ j  ]% _) a
2 q+ ^' k- R0 j, W% b9 C
return select(a, 0, n-1, k);
& {) z+ l/ M* G! y, n
8 u! s; s4 u$ n1 I( M  ^# J}$ o4 D* z) M! A8 K. y2 H
( r. i/ y8 P3 T1 s8 Q8 A8 h
template<CLASS T>) Q$ o- l1 v# ^; \' \; ?! _! M
: j$ U% R6 N; ?4 z. ~7 ^7 q
T select(T a[], int l, int r, int k): a/ A. \$ t+ R5 E0 p% R8 _
4 u$ K4 j7 T6 v- x2 b
{// 在a [ l : r ]中选择第k小的元素
0 K/ B& w7 r/ J1 @0 Q1 p. l& v# Y  N- K& Q
if (l &gt;= r) return a[l];8 f0 `( z. X& Z' |9 s3 m

$ b3 O) _- Z- I( Gint i = l, // 从左至右的游标
2 t7 I" c' K- c: @/ h6 E, ?2 p) r' J% K$ J- L
j = r + 1; // 从右到左的游标$ |' t/ Y5 E& @) l% x9 V

0 |1 d+ ]& [- ]T pivot = a[l];3 `+ `- t  C4 f; R4 y- R( V9 H/ Z
9 m* `, L" R2 b" [4 i% r
// 把左侧&gt;= pivot的元素与右侧&lt;= pivot 的元素进行交换
  }  _- C7 [0 j' f
9 h; l) {, V$ ~while (true) {
; n& h$ Y+ @- A2 Z3 N$ r' u
* g" u. Z# s( U* G+ r" U3 a7 Ado {// 在左侧寻找&gt;= pivot 的元素* k+ r! Z5 k+ d; Y7 U) A

4 X; `7 d4 I. C4 y" G8 J- ^i = i + 1;8 ?6 s& X  f8 \" Z
/ R: C/ n, |% Y, J( v8 u
} while (a &lt; pivot);
7 V  R# U- b/ w: r( ^
# F. [- K7 y+ Rdo {// 在右侧寻找&lt;= pivot 的元素
, @7 H5 L: D: i4 m: V
* q0 |8 J2 I! G5 a' aj = j - 1;* g5 U( h: ], P, F8 m' O) P3 E. Q

) n. _+ s+ T6 `  X! a! A} while (a[j] &gt; pivot);3 d/ _6 p$ O. C5 Y8 L- c' H
: \) l9 [! g" V2 k- m% B4 T, r
if (i &gt;= j) break; // 未发现交换对象
1 d5 V/ e$ u5 i# ~, S  Y# A8 m8 x5 n' s3 x
Swap(a, a[j]);+ }- _: L( E4 d' {

( d/ A: _+ A7 r. [}% Q# r  A3 j8 C4 [" ]4 e; J/ m
( }1 Y# M/ C2 D  S
if (j - l + 1 == k) return pivot;% `  l7 ^$ x# q% d' i" m1 `
9 |5 }8 k  s  o3 s2 w: l; {
// 设置p i v o t
: P  k' @& o3 x  [+ `" O) H
7 z: U% C- ]$ d3 I$ X9 Q% Ia[l] = a[j];6 W8 s! h  @. C/ _' q1 P& A
7 P# N: v! C2 S' s: _
a[j] = pivot;: N" O4 @0 u: d0 w3 X  @1 o' S$ q) l
! I( k0 k! M3 W& h, d6 l* R
// 对一个段进行递归调用
7 o( q+ Q% M) W& U+ c7 x; D- ^& t; b; M8 f( n- n! Q
if (j - l + 1 &lt; k)
, `  s$ z+ A2 b8 _- K& q" F6 m, Q. T
return select(a, j+1, r, k-j+l-1);0 I  K3 M7 D( ~# U
  U% W4 [4 E% I
else return select(a, l, j-1, k);* Q4 x" L# ]' _; _9 b0 h8 K

" }$ H, M5 `) D4 U9 i3 I' G  h}# b8 C. a2 h2 w- X. [0 K
" E  j/ a/ U$ U/ q5 |( i8 ^( h
程序1 4 - 7在最坏情况下的复杂性是( n2 ),此时left 总是为空,而且第k个元素总是位于r i g h t.) k: W8 D4 F0 j5 D

  P" u; W! {) z/ E6 y! J5 K4 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 个中间元素,递归使用选择算法,求得所需要的支点元素。
/ k. g! v6 Z) z% V  M
5 a/ Q6 `0 [9 P+ e例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 ]。
3 U) s9 d  d$ M! I* @9 U( [8 b7 M5 B/ W" p
如果要寻找第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 )个元素。
& p! |3 I% z: R6 v# N. n: }- Z# i8 {" c
定理2-2 当按“中间的中间”规则选取支点元素时,以下结论为真:+ p; s, G( N- y0 k. r5 i/ |8 T( ]

% n3 }1 s5 i8 r2 p) D1) 若r=9, 那么当n≥9 0时,有m a x { |l e f e|, |r i g h t| }≤7n / 8。7 ~+ ~( k& X1 @$ [7 j" h- X3 ]

& f' ^# W) E& b1 @2 @9 F2) 若r= 5,且a 中所有元素都不同,那么当n≥2 4时,有max{| left |, | right | }≤3n/ 4。8 Z3 H! B, w6 [9 N8 R
3 _& k0 X7 h6 I
证明这个定理的证明留作练习2 3。, F6 w9 H4 ?" W, o

( i  y: b/ b' u' ^. s3 W0 R根据定理2 - 2和程序1 4 - 7可知,如果采用“中间的中间”规则并取r= 9,则用于寻找第k个元素的时间t (n)可按如下递归公式来计算:" k7 |6 U. E' M3 r5 |
5 N9 E! Y2 X/ X
在上述递归公式中,假设当n<9 0时使用复杂性为nl o gn的求解算法,当n≥9 0时,采用“中间的中间”规则进行分而治之求解。利用归纳法可以证明,当n≥1时有t (n)≤7 2cn (练习2 4 )。3 J+ }$ A2 C+ j$ s' U4 c$ J& f

  ^4 V9 I& ^0 M! a& Y6 I2 X8 w当元素互不相同时,可以使用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-6-11 21:35 , Processed in 0.415615 second(s), 51 queries .

回顶部