QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 3460|回复: 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时被返回。
6 y3 W* t0 B. g. p8 |# y/ X: c2 I) \
* P  W9 {9 }7 e# q# i% J" C选择问题的一个应用就是寻找中值元素,此时k = [n / 2 ]。中值是一个很有用的统计量,例如中间工资,中间年龄,中间重量。其他k值也是有用的。例如,通过寻找第n / 4 , n / 2和3 n / 4这三个元素,可将人口划分为4份。
5 {4 p0 ^4 b: v
5 E( z3 l: F( P选择问题可在O ( n l o g n )时间内解决,方法是首先对这n个元素进行排序(如使用堆排序式或归并排序),然后取出a [ k - 1 ]中的元素。若使用快速排序(如图1 4 - 11所示),可以获得更好的平均性能,尽管该算法有一个比较差的渐近复杂性O( n2 )。7 m) U; v/ T2 v

2 Z! b# N. a4 O1 q1 |  c可以通过修写程序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)。
( L& J& L) s5 T( @
) \4 e1 E( L# o+ u" A% S程序14-7 寻找第k 个元素9 {, a: V2 w; q5 h2 h1 T4 f9 [
; l- A6 J4 |' r3 X( p5 ~2 J
template<CLASS T>
* u) I6 D% l( v/ X, n
, Z7 h$ I; f' t' d6 d  AT Select(T a[], int n, int k)/ D. x) S$ d& \& r
2 E& ^/ k  b3 z4 W: T
{// 返回a [ 0 : n - 1 ]中第k小的元素3 H5 H5 c8 l- y9 ?) a. @

" Q6 X) s* `. _$ X// 假定a[n] 是一个伪最大元素
3 s6 c$ P3 W3 }3 |. H, I0 h' a1 {
4 B+ y' L, ~0 g5 H4 Oif (k &lt; 1 || k &gt; n) throw OutOfBounds();
0 q* C6 B, q" C3 j2 E. t$ [7 F
8 q8 }' q; Q! D( d+ s. u5 \; Mreturn select(a, 0, n-1, k);
' F4 p7 ~* V. D4 J# f
8 ?1 T& c- r: c' y3 x4 K}. e; X3 q% [4 A! t6 K- y

% l" A  _: O3 Stemplate<CLASS T>
. v1 g; V  s) U& Z- z4 s
9 J- o- M& f* R/ T( G# bT select(T a[], int l, int r, int k)9 l7 M% W1 f3 L8 P- H$ E) D# v, u4 n  `
1 O/ U5 ]. |- @2 @
{// 在a [ l : r ]中选择第k小的元素. w1 ?" m. q" E6 _8 A& s; `

3 }# Z- T& P2 a' jif (l &gt;= r) return a[l];0 r2 n' ]2 x/ f/ O6 z
+ y2 t+ T# N- @+ _( `
int i = l, // 从左至右的游标  ~3 B% B! Y* c9 Y2 B4 @5 S

" J0 d4 {' w3 ~$ kj = r + 1; // 从右到左的游标# J4 `# ?7 i' I$ e7 ?
/ @/ V1 b" O* H$ c$ o
T pivot = a[l];8 w5 v/ B$ D3 c

6 Y+ [8 y& L4 P4 L6 p// 把左侧&gt;= pivot的元素与右侧&lt;= pivot 的元素进行交换; w2 c3 ^# d6 {# ^+ v6 E
& w" ?6 s  r7 F" h' m
while (true) {
& t$ b9 g- b# i6 w/ {6 G* `
0 L) |& z6 N! N, @. L6 X! w& @- a4 Xdo {// 在左侧寻找&gt;= pivot 的元素) O3 _" ^  ~0 n
6 j- w# O  U0 i8 x3 k# F% B
i = i + 1;1 c2 {& j& v* Q: D' v3 ^$ q

- Z. D" a! u( Y  t} while (a &lt; pivot);( i# O* i) M4 a" X
9 P8 @( C3 ^/ j( Y( x
do {// 在右侧寻找&lt;= pivot 的元素- t6 ]8 O/ a. w) n! U7 T) m
- Q& r/ L* B. H7 z! M/ q
j = j - 1;2 Y6 o3 C; a# v% @6 v# I8 u3 |
) f, [5 K* x3 m' A2 I1 Z3 W
} while (a[j] &gt; pivot);, }! X5 _  C, b. q

  d% `6 I0 L) mif (i &gt;= j) break; // 未发现交换对象
# L3 s9 C! o6 G) Y6 Q$ `8 b2 T4 |! w" d+ ?. z
Swap(a, a[j]);& F" u0 h9 Z3 H2 u, l! V7 N8 |

' @. f, C4 V1 B# N! F' C2 g}) z! U& I+ j1 c0 G9 W5 C1 Q
0 [( n$ \3 ^& Y  Y0 {( [6 @
if (j - l + 1 == k) return pivot;
' n0 D, i. ^% C; A- J3 {9 t& ~$ J. l/ k1 h0 p
// 设置p i v o t9 }+ _2 \$ r) J) I

+ J: x" j) V) ]1 D9 S. j! o! xa[l] = a[j];4 Z0 {' B5 H5 `" K6 H* i, ~

- s1 W' n& p: ~3 ?" J! {a[j] = pivot;6 z3 I6 |5 @: x! y

) f8 m" ^- a" ]3 k// 对一个段进行递归调用
* t/ a, J; C# x
( G4 `% C8 P! M6 }if (j - l + 1 &lt; k)% v6 p$ D( \( N/ G5 k5 i2 @
* P* p( a1 J! `# w! X
return select(a, j+1, r, k-j+l-1);; R" v1 N1 b0 K' Y7 x% Q
- V! q# N, E* M  F' a6 X
else return select(a, l, j-1, k);! e: a) m2 n+ G" {# w5 F) `8 Z
6 r9 g% T4 @( b' M4 d. e7 K( A
}
5 ?' E: l0 t  a, a0 c, P$ b* P3 B0 d) ?+ e
程序1 4 - 7在最坏情况下的复杂性是( n2 ),此时left 总是为空,而且第k个元素总是位于r i g h t.5 Y+ [" [4 @" [1 P2 K: r
# s1 p/ T# [! Z( k
如果假定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 个中间元素,递归使用选择算法,求得所需要的支点元素。
5 O+ G1 G: E( v% M5 m/ D* q0 v* \% @3 J( }# d# r4 X. q: F
例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 G( P! V/ b8 ^5 w  b" ?' I: r

: j  N) \4 z9 h7 _0 F如果要寻找第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 )个元素。
6 |3 F- a. K5 c9 _0 Q( Y: H$ j2 l" {. e
定理2-2 当按“中间的中间”规则选取支点元素时,以下结论为真:
- x, J& K4 w) K0 v& u' n* r
: l7 t8 ~7 E( b& F8 \; V! m1) 若r=9, 那么当n≥9 0时,有m a x { |l e f e|, |r i g h t| }≤7n / 8。( v- c7 l9 a5 v! @5 u& _0 b
8 \* g0 Z/ L0 A: a) Z
2) 若r= 5,且a 中所有元素都不同,那么当n≥2 4时,有max{| left |, | right | }≤3n/ 4。
3 ^( U2 M4 i6 a+ D) Y2 t) e% j% L. R# D6 |9 y" d7 @
证明这个定理的证明留作练习2 3。
0 J1 d& N- C6 \3 n2 X8 r2 Y! _" E* v, f! b8 @
根据定理2 - 2和程序1 4 - 7可知,如果采用“中间的中间”规则并取r= 9,则用于寻找第k个元素的时间t (n)可按如下递归公式来计算:  s# i0 v, C( d5 j+ A: |
7 D$ e9 A; i& f+ ?' w, |/ ~/ o
在上述递归公式中,假设当n<9 0时使用复杂性为nl o gn的求解算法,当n≥9 0时,采用“中间的中间”规则进行分而治之求解。利用归纳法可以证明,当n≥1时有t (n)≤7 2cn (练习2 4 )。  x; i+ `; A' }
+ o' ~1 A, n0 f) u
当元素互不相同时,可以使用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-23 09:06 , Processed in 2.329180 second(s), 51 queries .

回顶部