" }3 ]" D4 j7 R7 up u b l i c :9 _" {. ?" l" h1 o: v
9 B+ G* ?4 ?* M. b8 C* Tint operator<=(Point2 a) const 5 P, Z; O8 }2 D3 w . {9 C+ O; h: U+ x$ x; O% n{return (y <= a.y);} 4 W& U* ? U8 l1 j1 k 4 ?& @) E5 _7 [, Gp r i v a t e :: C [2 `: `/ |
: r- p) N. z" d
int p; // 数组X中相同点的索引 " r9 T8 F' n/ g/ ~, @) |# ` c* F' p- E; m- q5 p. U+ efloat x, y; // 点坐标; C9 m9 x& v6 A" S" y& h* z4 ]; F5 g
0 n1 q5 I* z6 {5 b1 @} ;0 H- ~: T: e: ~# R/ @
. `9 \0 ]& g5 W2 K所输入的n 个点可以用数组X来表示。假设X中的点已按照x 坐标排序,在分割过程中如果当前考察的点是X [l :r],那么首先计算m= (l+r) / 2,X[ l:m]中的点属于A,剩下的点属于B。计算出A和B中的最近点对之后,还需要计算RA 和RB,然后确定是否存在更近的点对,其中一点属于RA,另一点属于RB。如果点已按y 坐标排序,那么可以用一种很简单的方式来测试图1 4 - 1 6。按y 坐标排序的点保存在另一个使用类P o i n t 2 (见程序14-8) 的数组中。注意到在P o i n t 2类中,为了便于y 坐标排序,已重载了操作符<=。成员p 用于指向X中的对应点。( |; T* {4 V7 z( u9 Z" \
, l7 A, M$ X% K: d* J确定了必要的数据结构之后,再来看看所要产生的代码。首先定义一个模板函数d i s t (见程序1 4 - 9 )来计算点a, b 之间的距离。T可能是P o i n t 1或P o i n t 2,因此d i s t必须是P o i n t 1和P o i n t 2类的友元。 ! X8 L+ R9 U! K, L) p t$ w $ ?) l! s- I- z! c/ X0 H4 _ S程序14-9 计算两点距离7 h4 m2 N% K' w E. {7 H
4 b3 p X$ m( T# m# y+ t+ ?template<CLASS T> Z0 M4 G& y" l! w# c/ h7 |, ~$ D$ ?: o
inline float dist(const T& u, const T& v)* [( M( N3 I+ f; A
- m* z3 M* X% \3 G1 y- B+ O{ / /计算点u 和v之间的距离 4 B9 e3 h/ @9 C0 [1 V- C+ y - j; O, k# x5 D, y! V7 G6 Y6 |float dx = u.x-v. x ; " x5 y9 P J+ h/ R: @! } Q. ]/ d- k! x8 y. B/ l" i. H" G/ a/ g8 r
float dy = u.y-v. y ;6 n6 _' w' L+ `$ V0 H) T! S/ ]
# {/ R- y) E1 X+ r3 q( |5 ^return sqrt(dx * dx + dy * dy);8 a" j1 r. {' v) v- r! v! ~
0 h5 J; d4 z6 U# M1 Y0 ]) ~
} 9 b/ s" b0 w# r; _: d; l; L0 ~ + m( a1 s; j y f6 Q1 {/ b% S3 a如果点的数目少于两个,则函数c l o s e s t (见程序1 4 - 1 0 )返回f a l s e,如果成功时函数返回t r u e。当函数成功时,在参数a 和b 中返回距离最近的两个点,在参数d 中返回距离。代码首先验证至少存在两点,然后使用M e rg e S o r t函数(见程序14-3) 按x 坐标对X中的点排序。接下来把这些点复制到数组Y中并按y 坐标进行排序。排序完成时,对任一个i,有Y [i ] . y≤Y [i+ 1 ] . y,并且Y [i ] .p给出了点i 在X中的位置。上述准备工作做完以后,调用函数close (见程序1 4 - 11 ),该函数实际求解最近点对。 3 R( [; K: i9 a! i! K/ O$ U3 d' F6 a+ Y. U+ A
程序14-10 预处理及调用c l o s e 3 B8 A, b+ T# a% _2 } 1 i5 l ~, K3 ~ U* v' }! Vbool closest(Point1 X[], int n, Point1& a, Point1& b, float& d) " v- V) [' p+ d% h - a {" T5 Y+ l{// 在n >= 2 个点中寻找最近点对 ' T* X3 R% ?1 f9 M0 d& r" o% a; n4 L3 S, M" Q2 u5 B/ S, O6 k
// 如果少于2个点,则返回f a l s e 3 P# B5 Y* a, I4 n" Z7 J3 Z 9 S2 Q# b: \: U$ ]( f2 J// 否则,在a 和b中返回距离最近的两个点 ; X0 E* ~5 ~) r# p8 @/ y4 i- X ; B! |; f" p% z0 E Xif (n < 2) return false;! l3 c' Q1 ?1 m/ F6 @
# G% T3 U. z+ \6 l// 按x坐标排序 # c$ a a0 i' Y* d9 c* }' y" f3 l6 f/ r7 X& P, \% F
M e r g e S o r t ( X , n ) ;) p, O: C. {& q# H$ | x5 o1 r
' @" i" { N: W3 S8 q" V// 创建一个按y坐标排序的点数组 7 R$ [. e/ N; e , T/ ]& `& G8 T/ XPoint2 *Y = new Point2 [n];, x' B) E' Z, N* u1 y3 v2 K
. X& b2 E/ e Y9 ^3 i3 Yfor (int i = 0; i < n; i++) {/ |. [% x' O/ B X8 C. w! Q7 q! `0 C
6 _& X% b% }2 T4 H# N( p
// 将点i 从X 复制到Y4 _# m7 V" q3 a; Y' Z
+ Y2 V0 S5 T! T N8 |
Y.p = i; 0 q& d' _# t! R* s( T$ b8 J$ }* G1 _$ V+ n% l- E
Y.x = X.x; & H" V5 V% g: D & y. k) U. T0 f. H' ?Y.y = X.y;" E( U/ _% C/ E* F% L
* E- D( `( q* F& Y9 D
} # F- {# M! \3 O: Z: @6 X. Q( p1 l: h& V' I' W* P
M e r g e S o r t ( Y,n); // 按y坐标排序 ; ~6 z4 B, a& B7 p / f" c7 Y; H5 B S// 创建临时数组 ! G( C/ Z- \% p& s' C9 f: v, F; \0 `4 Y( q! Q$ u4 _1 F: ^/ a
Point2 *Z = new Point2 [n];$ z1 k0 h, u7 z$ U0 |
3 B2 {% J# y# h8 s8 Z
// 寻找最近点对1 h$ U6 V+ |- [" L9 D) s
! N, k3 Y( @2 a @
c l o s e ( X , Y, Z , 0 , n - 1 , a , b , d ) ; 7 m P( O- Q& d # W9 K3 ]) Q; | ?3 W) H2 S+ B// 删除数组并返回 3 B8 i& l6 _6 R6 Z( L6 e0 k % |2 L5 D! f0 f: xdelete [] Y; - ^& f2 N$ a+ B' ^# o. M+ y% @" |, R* `2 E* l5 x
delete [] Z;& b7 |, [& O2 W
* a, `% E# M% K' l, x, Dreturn true;. L! Z1 @8 O+ o" |
3 D* }9 K9 J' b0 o8 [! T
}6 Z1 ~. ]3 v( j0 t o; i4 E
( f+ A; b6 I4 O, w; y
程序1 4 - 11 计算最近点对2 q2 |( J3 |8 }$ ~9 O
4 @! v- \+ y7 a' G5 zvoid close(Point1 X[], Point2 Y[], Point2 Z[], int l, int r, Point1& a, Point1& b, float& d) + c+ `) ]8 G# ^0 o* F7 t0 `, r* l
{//X[l:r] 按x坐标排序' E% s3 k/ Z% D" A; t
- r" b' i6 d+ C3 U/ j! e7 B5 e
//Y[l:r] 按y坐标排序3 j, q/ P/ a( H; i, A' |1 H- y( I
# ]0 W: K/ D! {; C% L5 E* b2 ]% _! x$ ?g = m+1; // Z[m+1:r]的游标 + Z+ r; z( N- b* D+ @, u; l3 c) a$ Z- J f5 E/ |2 C, c$ [; P! f3 J
for (int i = l; i <= r; i++)3 L: b1 Z& Y8 \
: } J5 J, _0 B7 ]! Z' B& A
if (Y.p > m) Z[g++] = Y;( x! m% m" R2 w5 A; Q! U
0 h+ v6 W* _! T1 H& i: _5 Z
else Z[f++] = Y;4 y; m, ?* C J+ h1 I }
, ^, o) ^7 w- w! y& F% K7 n2 R// 对以上两个部分进行求解 $ S( Y& p- d4 l8 I5 u) z* T 2 n- G$ N0 F( Z/ rc l o s e ( X , Z , Y, l , m , a , b , d ) ;) O- ?$ W8 ~- q0 q; ]- n
- p4 K; ^6 Z3 Q2 M
float dr; ^1 T' s* I L8 n7 w/ v4 |( x6 `$ |; A! q) Q. x) r z4 [
Point1 ar, br;, P' K" E$ l% t# ^6 y
, C' I ?% f+ N& \c l o s e ( X , Z , Y, m + 1 , r, a r, b r, d r ) ; 9 V5 T' z( z5 t! x' M) Q# G- V8 L' a y& l. Y5 k. r: `0 [
// (a,b) 是两者中较近的点对+ X/ u* W8 `! L( Y
' X- S( R$ x' \6 h
if (dr < d) {a = ar; 3 M6 u+ O. n9 M) I/ B0 M + s8 v3 i2 x' U& E0 Y% Jb = br;7 x; X2 D# A: J) j! r1 c
/ V& |/ R" Z2 G. T7 }$ |6 T% `. z
d = dr;}( o ?3 g# [( {! V+ i/ {% G
& J i6 h' n# i1 U2 C
M e r g e ( Z , Y,l,m,r);// 重构Y 9 O) `7 S* L- n) [) K, m- L I4 ?# z, M) d/ /距离小于d的点放入Z / y; v% G- W# q! D9 }& N+ a2 z- Y0 r( U5 ]2 J$ o5 O4 f2 o! J( o
int k = l; // Z的游标 0 ]' V. u. c1 E* a7 I8 q7 |) s! t9 z/ F7 n; C# t- @
for (i = l; i <= r; i++) ) h5 }- |8 s& \1 O' f1 l* U. F9 R ) t% }2 _7 t9 f5 m( l8 G+ Hif (fabs(Y[m].x - Y.x) < d) Z[k++] = Y; " f7 T; R( F4 v . r/ Q( V6 O. [- E- _ s& v// 通过检查Z [ l : k - 1 ]中的所有点对,寻找较近的点对 i; x' ^, C* h
7 ^) g* G- [8 |+ m- Z6 L, p& u
for (i = l; i < k; i++){$ L2 w @- [4 o9 A+ x3 b# d7 `0 ?$ W
, Q+ X' Q# s$ P/ r, m2 S9 \! R3 F
for (int j = i+1; j < k && Z[j].y - Z.y < d;/ A# T: Y) a2 w
7 M# T D4 {9 i! l( A. w/ U4 l) cj + + ) {" x2 H( ~( u5 }3 B3 b; p
8 }8 v; p# {2 e5 }这个递归式与归并排序的递归式完全一样,其结果为t (n) = (nl o gn)。另外,函数c l o s e s t还需耗时(nl o gn)来完成如下额外工作:对X进行排序,创建Y和Z,对Y进行排序。因此分而治之最近点对求解算法的时间复杂性为(nl o gn)。</P>