v5 q6 A: s3 A/ q: j* jp u b l i c : : H6 U- b! A+ v" z7 A. P" N l! R8 B- j& F/ n5 B
int operator<=(Point1 a) const0 m* \5 [4 J3 S0 s' s2 W+ h
* p8 _/ t+ R2 x* q
{return (x <= a.x);} # G1 i% _# V+ J7 r8 e( n' h r; c5 {5 g( I$ D1 R
p r i v a t e : - S, j% z) k; ^5 J5 F% u 6 p9 |& i9 C C) r. Wint ID; // 点的编号 ; U) z6 f' f+ d4 R; ~$ i* S4 `2 `' J4 H, S8 ~$ S- c- Z! @+ u1 \5 N
float x, y; // 点坐标 , o. `0 P. n, k. w l8 c * Y" Z# V K, b' o} ; ! S3 G2 J6 u: E/ q5 }2 v5 U; \9 ~4 B
class Point2 { & x- H5 A/ n1 M' ]( D9 J) E { ' q3 [0 S* r2 L3 I" c5 gfriend float dist(const Point2&, const Point2&); / W7 @- m% b' Y) _: ^8 i- _9 ^1 j1 b % e; f% H' L" X7 g' |& Ofriend void close(Point1 *, Point2 *, Point2 *, int, int, Point1&, Point1&, float&); O- ?2 ^. m6 I: |+ H
- S$ p0 J( j7 S2 n% V3 Z; r, t2 V# l
friend bool closest(Point1 *, int, Point1&, Point1&, float&); " }$ r! `! N' k7 M# C) L4 X& ` A$ O H. A; L) B' \friend void main();3 n0 ^6 P$ h$ V' p, c. s- a
$ \" N& \ g" y: y, W- x
p u b l i c :& D0 n2 ]. j1 Q# ]# J
9 F6 g( T& w3 {7 k6 |2 Z
int operator<=(Point2 a) const 2 J/ T0 T& V! S( Z' x& D9 m8 B* S' M$ K% q% ~5 v0 n- ~
{return (y <= a.y);}& h5 [0 W8 b4 w# A
. t" G4 P) K& e0 Q1 I8 a
p r i v a t e : ) w/ s3 Q0 y, {" z: A$ T2 @+ j/ t+ [
int p; // 数组X中相同点的索引 $ q) l1 z) Z2 ^4 V8 h 5 t# ^# a0 ]4 e9 Cfloat x, y; // 点坐标) \: M9 T" v/ E8 }1 a( ]
6 I1 Y5 O3 J! l7 f; n, t} ;8 r5 F! C* @$ [, \$ E1 C
! d* \% ]. m- \/ w* I8 d所输入的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中的对应点。2 k" i( J8 h) Y0 O2 [: l1 D0 o
; b& Z- s" R! J0 O
确定了必要的数据结构之后,再来看看所要产生的代码。首先定义一个模板函数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类的友元。 1 ]4 J1 h, ^3 _( { E . Q, q; }& U5 e0 h! z3 f3 I f6 F程序14-9 计算两点距离 2 q5 M9 R5 u* J0 s' i# a8 b0 d' @ 7 A7 K" m. Y: ztemplate<CLASS T>/ }* b$ B" k7 o9 h2 T
5 l* P" W; h3 X$ K& v
inline float dist(const T& u, const T& v) : e) Z! L5 ` c0 n+ } R4 B . g) p' P' }* N' A$ D: B [{ / /计算点u 和v之间的距离 7 n o' O) s6 K# P, n3 a$ p* c6 ]8 K; V
float dx = u.x-v. x ; * m5 ]7 A2 k3 \9 [' A. r6 R+ z3 B- g0 Q+ A$ F* x
float dy = u.y-v. y ;6 r; o# x/ @4 G. x: F: @; e
Z3 x4 w$ ^& p5 ^; M7 v
return sqrt(dx * dx + dy * dy);7 Y% H/ F- Q* Y$ T4 w
3 `4 p$ L f& w! T4 n J9 R; o
}8 g% n0 r S' t+ W
3 _- K$ P- h; M1 b/ |& g/ L, i如果点的数目少于两个,则函数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 ),该函数实际求解最近点对。 8 h' K8 d; P1 D& C4 d: g % o2 p* a5 l: R/ W% }程序14-10 预处理及调用c l o s e 8 k* E2 D1 m( a7 n% X, @! z# c& f: F# p6 b
bool closest(Point1 X[], int n, Point1& a, Point1& b, float& d) * ]1 e0 H8 _3 t- E& ~+ x& U 6 O; S. @& Y4 n# |3 P, A0 g( j' q{// 在n >= 2 个点中寻找最近点对 / s" M; u- \! v9 Y / Y$ h6 y; j z// 如果少于2个点,则返回f a l s e& ]; J8 r, C0 R' B& c' O, k
4 ~" [; v) N2 t' b% Q# k程序1 4 - 11 计算最近点对 . i! c2 v/ N' K2 n% ^+ C: C & p9 w% d5 l4 e% ~void close(Point1 X[], Point2 Y[], Point2 Z[], int l, int r, Point1& a, Point1& b, float& d)) v1 f8 s8 M2 {& r7 w( p
8 n( f0 p, ^ p, M! @
{//X[l:r] 按x坐标排序 - T; ^5 S$ |0 `6 |& y @ ) X9 |- i$ ]! [( { ^//Y[l:r] 按y坐标排序 % x8 ^3 _& ]4 _ $ I0 w5 o9 v6 i, x/ X8 tif (r-l == 1) {// 两个点 ' t: A k' n- s# J) F+ {- S3 ` + r% c' }- N- e5 T# M$ P3 za = X[l]; ( z2 Y- o) z8 q6 w T. w* V* Q; p6 c& j! P- I
b = X[r]; 2 b* @9 N# M( ]- {! k. y3 T- U+ o- g& a# L6 G) y. S8 v
d = dist(X[l], X[r]);2 F! j& y7 r5 F$ C9 n
9 W1 G, Q6 b f* c7 `! Tr e t u r n ; }# G2 O- ~+ Z' q5 L$ N n
- M: b. E. |4 K& M/ B/ rif (r-l == 2) {// 三个点' {' |( }0 ?$ F4 @' T
7 B3 b3 W5 e) f' }9 J. t* V( V// 计算所有点对之间的距离 $ C% y, q v8 t4 T: e 1 s+ C$ ?% S, j+ w) Zfloat d1 = dist(X[l], X[l+1]); 9 c6 s, a: q( b! {2 l! D0 G$ T# t; c9 ^2 Z" f; |( I% s
float d2 = dist(X[l+1], X[r]); ( k% f) d. `# W& k* v$ i5 l% K! C8 \4 ~ L' w1 F
float d3 = dist(X[l], X[r]); ( U2 I4 a& y/ Q# }" L : f& ?9 Y9 T n8 q( O. o* j// 寻找最近点对8 Y" h1 C7 p5 q1 I
+ C; @ a8 n" i- Y
if (d1 <= d2 && d1 <= d3) { $ A6 Q p" O% ^7 r ; k6 y) L+ g, z: na = X[l]; 4 \1 W" G- f- C# W! ?+ C+ N2 A1 Y- x: K5 C5 a; }4 f+ _1 w
b = X[l+1]; ( p, Z1 Y8 ^( o 1 i( q1 Q# o) H" ]4 d% i8 O, fd = d1;. `( [9 |0 Y- N% I
$ n3 S' b6 Q% Z7 i
r e t u r n ; } ) J3 W& r. L/ Y9 I* u5 } 7 j, U( P/ z- n1 ~% E$ F' h7 Rif (d2 <= d3) {a = X[l+1];* j0 i9 i6 e M- v6 C5 v' q
V) `( Z" }' k' U
b = X[r];5 q3 M9 W+ {" ~* p4 S
7 X2 K Q j, w+ E* w' D sd = d2;} % p% _' v: B, `1 C8 o/ ~$ Z9 m" w0 ^; x4 g# d- k+ m: O
else {a = X[l]; y& g. N$ b8 g. h7 v0 U8 b# y9 d! g* \; o2 r v* K+ Z6 @
b = X[r];- c) f$ K4 K9 G. M
( \: D( Z) b, J4 D4 U( Y& o
d = d3;} , w' B$ f3 K' y! v" I8 r& r2 `7 q9 U2 s* @- S
r e t u r n ; }! v# m1 h, O7 `0 A
/ X' E$ a# r% T9 {7 e5 T L
/ /多于三个点,划分为两部分 7 g; |0 B6 ]; C$ D5 r ! k3 |4 s( g- l7 q# j2 q1 n; Hint m = (l+r)/2; // X[l:m] 在A中,余下的在B中 ) t* f) u+ t. g( Z D: j1 Z8 g5 ?4 R: X. G2 i/ \// 在Z[l:m] 和Z [ m + 1 : r ]中创建按y排序的表 . ]! }+ E3 @( x h+ X3 E2 E1 l4 _2 F2 w4 S5 ~/ K6 c
int f = l, // Z[l:m]的游标5 x3 w& Z1 b! _# t, O
( S+ h' m* S: {" u2 s
g = m+1; // Z[m+1:r]的游标6 s0 _' p8 ]$ Z5 y b% x
& S6 F, i8 K$ S. Ifor (int i = l; i <= r; i++) 3 S2 O6 k3 [8 i9 [! T& h4 R. f' P/ K/ o# W7 D1 W% n; p
if (Y.p > m) Z[g++] = Y;! F" E k, V; k' `) v
* u- Z* D9 c) V( q9 C, j/ r# felse Z[f++] = Y;) o' ]+ G5 E9 t8 S! L
, D) g7 e1 d; b4 U' t6 P/ o// 对以上两个部分进行求解 ( d# m* E8 x& H" X( M! Z7 R- P
c l o s e ( X , Z , Y, l , m , a , b , d ) ;, t m$ |8 b/ M" y. l" o! R
. J. ?% J8 K# v3 _+ T4 ~这个递归式与归并排序的递归式完全一样,其结果为t (n) = (nl o gn)。另外,函数c l o s e s t还需耗时(nl o gn)来完成如下额外工作:对X进行排序,创建Y和Z,对Y进行排序。因此分而治之最近点对求解算法的时间复杂性为(nl o gn)。</P>