QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 3376|回复: 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时被返回。
$ [- g, t; K5 b" J, V
/ D3 [/ u6 ~9 U& ]选择问题的一个应用就是寻找中值元素,此时k = [n / 2 ]。中值是一个很有用的统计量,例如中间工资,中间年龄,中间重量。其他k值也是有用的。例如,通过寻找第n / 4 , n / 2和3 n / 4这三个元素,可将人口划分为4份。
/ D- z+ q1 P" v+ _, C2 L7 j0 R  i" ]+ b" n9 H; Z7 T( j
选择问题可在O ( n l o g n )时间内解决,方法是首先对这n个元素进行排序(如使用堆排序式或归并排序),然后取出a [ k - 1 ]中的元素。若使用快速排序(如图1 4 - 11所示),可以获得更好的平均性能,尽管该算法有一个比较差的渐近复杂性O( n2 )。
+ O2 H0 g5 Y7 x! {9 v  B4 F0 Y8 w" k
* Q! ]% j: n5 Z! Y5 P可以通过修写程序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)。
) e6 ~" e8 |: G; N
" d) P7 M5 ?( [% }. c$ F程序14-7 寻找第k 个元素
( |! I) e# ~, @# [4 k4 m7 z
4 B7 A% T1 h% w" jtemplate<CLASS T>' p' j  j) }2 O# H$ R- E
0 @* z. G2 N9 s4 v
T Select(T a[], int n, int k)
( B) m' N! }6 j8 b. R& W, N5 y$ k; g+ P) {* x2 Y, o/ b& y
{// 返回a [ 0 : n - 1 ]中第k小的元素
  r' H# k, W+ R* B: ^3 p. w* ^. a' u
// 假定a[n] 是一个伪最大元素' S; Q& C. M' e" C/ E! G, o

, h3 P2 B3 y# @- U2 [% D, E* Hif (k &lt; 1 || k &gt; n) throw OutOfBounds();
6 p8 E* F" }8 O$ Y2 K4 A  _9 K2 P6 h* n- K3 Q! V/ ~/ k; T
return select(a, 0, n-1, k);) _! j3 `0 c) P4 i& _: k, _

. i+ `$ ^! Z$ u7 `: s}) D, C9 W4 d. J0 @1 Y' z# n$ {
$ U. B2 O, [) q1 ?
template<CLASS T>
1 t% @& a4 _7 d; r6 n1 G' E6 m. I
' W) J0 t4 c2 o# R* M. `- rT select(T a[], int l, int r, int k)$ }' Z2 U4 _' D3 F

2 M3 `* y- N% |5 n4 ?{// 在a [ l : r ]中选择第k小的元素
9 D2 Z* {+ s# E/ w- i8 x, t  I" q: v1 A% s
if (l &gt;= r) return a[l];2 K" U) t) ?4 m1 [0 b

+ s; v; K, N2 z6 _0 e* O; ]3 Bint i = l, // 从左至右的游标/ ^! N: y/ t/ |0 z( m$ _' J

3 J# X; s+ {# x! t; w; T: F/ r5 Ej = r + 1; // 从右到左的游标
* K. X& f. ^" `3 C$ H9 M0 y: [8 `  w) W2 d2 Q4 @2 s" n! A/ D
T pivot = a[l];* q0 e6 J# G: y+ ~& u7 q

1 T6 _& g" z+ {  W// 把左侧&gt;= pivot的元素与右侧&lt;= pivot 的元素进行交换, I) I; u+ W; P! Q1 l6 b

' V0 H. U: }" ~, m& Wwhile (true) {" G( G6 Z; y! n

2 v. Q# o+ s7 J8 ?- ]do {// 在左侧寻找&gt;= 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 &lt; pivot);
, k' H# |9 x* K4 y$ Q7 I/ a! D6 `2 @& q
do {// 在右侧寻找&lt;= 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] &gt; pivot);$ f9 h! ?: d$ c# l' i
0 w# h  _, o0 a" \$ U- j( X( H: h
if (i &gt;= 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 &lt; 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&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 )个元素。: 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>
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-21 14:59 , Processed in 0.418712 second(s), 51 queries .

回顶部