QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 3400|回复: 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时被返回。
8 u+ k% z8 b! w3 J
: y- L& T& t* |4 C( {" b' A选择问题的一个应用就是寻找中值元素,此时k = [n / 2 ]。中值是一个很有用的统计量,例如中间工资,中间年龄,中间重量。其他k值也是有用的。例如,通过寻找第n / 4 , n / 2和3 n / 4这三个元素,可将人口划分为4份。: j* @2 x4 r" N- R
' Z. G8 J+ h# V9 T$ P* B* L
选择问题可在O ( n l o g n )时间内解决,方法是首先对这n个元素进行排序(如使用堆排序式或归并排序),然后取出a [ k - 1 ]中的元素。若使用快速排序(如图1 4 - 11所示),可以获得更好的平均性能,尽管该算法有一个比较差的渐近复杂性O( n2 )。
& w8 H) S- ~: r; O! W1 ~
. P0 w( o7 I% j" e& A' E: e可以通过修写程序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 H) V+ k* c7 c$ w6 m
! S8 `3 ]6 A! G. L3 z) ?0 _
程序14-7 寻找第k 个元素) R: F- E2 q  N: s, L

6 i5 e( ~8 s* p4 {& L6 Utemplate<CLASS T>0 i/ s! M: n. d# ^9 U. B6 I+ P3 d" [
4 ~2 y% H; x* \
T Select(T a[], int n, int k)
* ~: ^$ k* n. i5 w; Q
0 K) S) j$ `& Z# O7 B$ [{// 返回a [ 0 : n - 1 ]中第k小的元素- `$ X( a2 O& z" j; {" S

" l0 F% w* g4 k) f  W3 c// 假定a[n] 是一个伪最大元素
. d0 z4 t  N9 _4 {: |8 n7 t5 a6 R# M! T- n. k  Y. p9 r( [
if (k &lt; 1 || k &gt; n) throw OutOfBounds();7 A: l# U, ~1 l

0 S3 J9 J( x6 {! ^8 N1 I+ yreturn select(a, 0, n-1, k);
2 }( P9 `2 }/ S" W$ A, H9 r: [9 N6 v( D  r+ |
}3 }4 o' K* s- E, x2 D/ l
& C" E. s. m+ C1 G2 A
template<CLASS T>: X  x9 [  s& M; f
1 w- U, F2 z! G+ x
T select(T a[], int l, int r, int k)
5 f# s) b3 P4 U; {& ~' K5 W# W
. v1 m4 x$ @+ z; C  q{// 在a [ l : r ]中选择第k小的元素* K+ D" C0 L* d% U0 Y8 R# v# Z/ `
* K( ?* y3 \$ U+ s
if (l &gt;= r) return a[l];
1 R  f3 Y7 I& m# `6 y
7 {- `, Y; e( ]int i = l, // 从左至右的游标# g4 E- x/ v1 `2 s6 o* _/ p
5 }& a2 q2 ]: x3 K0 b" Q( t  E
j = r + 1; // 从右到左的游标0 T, j) Y+ j; @7 A
" O+ K2 F( h0 J- w/ Y& l
T pivot = a[l];2 C  `1 L5 ^# ~4 I9 q6 P
* ]/ {9 g- `' w  s
// 把左侧&gt;= pivot的元素与右侧&lt;= pivot 的元素进行交换  r4 G7 N, h8 Y( f8 {* ?" K4 T$ z
% L' x0 r2 ^4 F7 v' S+ M8 h
while (true) {
# R# f8 R( J$ q+ u9 g5 X( f" r8 w; r0 a  N) x5 |3 z
do {// 在左侧寻找&gt;= pivot 的元素/ n1 Y! `# A1 o* M' c
/ q0 T% G7 i- E. w; c7 @
i = i + 1;8 d( z5 O- m. I7 L( J7 A
. ?' s0 {, p- _+ H7 Y' I
} while (a &lt; pivot);" a* m8 U, O2 b. D2 i/ {

' u! K- l$ G* @do {// 在右侧寻找&lt;= pivot 的元素- H1 n/ ~! |/ P1 t3 h
" s8 @9 K& `* K/ j0 p$ c# G" h
j = j - 1;# E, f% u- P5 C  X+ a

( ]1 ]8 c8 B& c} while (a[j] &gt; pivot);* H: @0 w# {) J/ D& l
; W0 o% f; U* Q1 t5 X
if (i &gt;= j) break; // 未发现交换对象) d( ?4 X- T1 }+ l0 |2 s( N
: h0 p6 J* E: a/ `2 t
Swap(a, a[j]);
" O$ v# \3 _6 E
$ h; |5 Q1 C5 q" m) X6 d}5 N0 x$ }4 C$ b. n
: k5 [6 W$ {, Q8 H
if (j - l + 1 == k) return pivot;2 i8 Q- D( q! r7 W$ G2 }

3 R. l, Z! y( h. |// 设置p i v o t+ C4 s; I- e0 A- M4 I' S

. s' d! h) K0 K9 ^) }- za[l] = a[j];
1 y" L; i6 v+ X1 a1 ^' n: E2 D2 I& s8 B7 F1 w" p4 Y0 `
a[j] = pivot;
' g( r( y6 X$ r
  C8 G' v% c/ H0 Y) M+ M% P  `7 J% U// 对一个段进行递归调用
# t) \/ p* J! g$ |- F
/ K4 ~; @( ?8 W' t, Y  }3 T2 O9 Nif (j - l + 1 &lt; k)
  _" Y# V9 `+ l: K: V
' m+ r% M0 W5 v7 J4 a. Nreturn select(a, j+1, r, k-j+l-1);
  M$ M6 W0 `: N8 |: B
  C$ M( ]# L) S4 gelse return select(a, l, j-1, k);3 D( ]* [( @( r* p. x8 Y
0 d: |5 d4 p# H! @# E3 P% S
}$ H. O; g$ ?" _; J, A
) H/ Y. M; l! h  p
程序1 4 - 7在最坏情况下的复杂性是( n2 ),此时left 总是为空,而且第k个元素总是位于r i g h t.
; o; g2 Z& x9 w3 E" n" X! n3 u# t2 n6 b
如果假定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 个中间元素,递归使用选择算法,求得所需要的支点元素。2 T7 S5 n8 t  W' _+ h& t

4 q5 U3 T, w4 S( f  d例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 ]。) `" v3 v- ~% W# o$ g/ k; `
2 s/ a7 I2 u0 A' ]
如果要寻找第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 )个元素。
# Z7 K/ X0 t# l* `$ v2 m% Y
- V# g6 U* T# J1 R& U& V6 N定理2-2 当按“中间的中间”规则选取支点元素时,以下结论为真:
! m7 u6 N. ]* W+ Z1 j( g* J9 U6 W3 H: l7 e* [4 {: Y, {% M
1) 若r=9, 那么当n≥9 0时,有m a x { |l e f e|, |r i g h t| }≤7n / 8。- ~) u) D! ~/ a8 E8 K3 {% e

' A0 e* s0 v# i5 h% M, Z2) 若r= 5,且a 中所有元素都不同,那么当n≥2 4时,有max{| left |, | right | }≤3n/ 4。
4 u% b4 }. h) I5 q& C
5 A8 T+ O5 p" P证明这个定理的证明留作练习2 3。( ~# o- D3 k7 L& ^5 F. ?2 _

. ?( ]: x5 v3 F  |; M根据定理2 - 2和程序1 4 - 7可知,如果采用“中间的中间”规则并取r= 9,则用于寻找第k个元素的时间t (n)可按如下递归公式来计算:! v% D: X- \: a, i( `# k9 {

2 }: c! X8 Z  C/ F9 k6 @2 ?在上述递归公式中,假设当n<9 0时使用复杂性为nl o gn的求解算法,当n≥9 0时,采用“中间的中间”规则进行分而治之求解。利用归纳法可以证明,当n≥1时有t (n)≤7 2cn (练习2 4 )。1 z7 Y* B) \# E! Z4 p! Z/ E
- ~6 j8 e4 t$ b
当元素互不相同时,可以使用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-14 01:00 , Processed in 0.440353 second(s), 52 queries .

回顶部