& e, u4 a" b7 E1 ?" t$ vfriend bool closest(Point1 *, int, Point1&, Point1&, float&); ; A) R5 x0 a) i5 T* P # |) o# n F$ F4 I) D" }friend void main(); & U; Q' }0 j1 u( S0 ^1 p, z: z5 V
p u b l i c : 2 h% `! f! J% j! e, {7 H( N / l$ G/ W, q& rint operator<=(Point2 a) const% ^5 }1 Q) o" p8 v; I
4 M- ?! @6 D; ~
{return (y <= a.y);}2 ^6 Q0 Z, c/ c/ I6 j
! S" v4 V- J) v/ X- M/ s4 op r i v a t e : 0 y! I4 ~/ w8 O0 ?1 I$ A" \3 s4 X. [$ J2 L) u
int p; // 数组X中相同点的索引 2 V* V @4 }& S3 D9 o 8 Q' @, U: ?' l/ i/ Cfloat x, y; // 点坐标 ' B! u" [5 l, e+ b8 z" e/ P$ A7 W% o- ]% Z0 F+ \+ w; C- }
} ; 9 N$ }/ A' X: m1 }& m, t" P8 S/ L 0 a! s, g& V) ]- [所输入的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中的对应点。 0 T: Z9 j5 D4 w/ w ]5 }/ W% Y: y0 }1 M: c/ w
确定了必要的数据结构之后,再来看看所要产生的代码。首先定义一个模板函数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类的友元。 8 n4 W7 u T8 X) n! J ; h7 b$ |4 _& \/ H+ C5 g8 h9 |程序14-9 计算两点距离 + a$ b1 B8 B7 A. Y 7 v0 u- T; c" z9 `- `2 `template<CLASS T>( T6 R9 D, }7 z: \5 u/ X$ a
; n- k; l, ~: C. x( E: A' ninline float dist(const T& u, const T& v); j% p: Q; _* k r/ e( @
% x% O0 r4 X- }5 u
{ / /计算点u 和v之间的距离 + X. Y& {4 M/ N7 \9 J( X7 ^+ H6 d: Y; I1 p" |* ], K. B
float dx = u.x-v. x ;) z; Y! P1 p7 y, x3 r- d
: c' B1 P$ X; F W, m! U% mfloat dy = u.y-v. y ;* @) m" e, A4 P1 @, A+ H
- [$ X* K$ N q+ N# D+ Ureturn sqrt(dx * dx + dy * dy); ; A Q) Z( `* Y3 f! y2 N M; C5 E , @; b- O# q5 \} r7 [/ n9 V; v7 N% ^7 c ! G y b# m( g# X( Q$ a2 y$ 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 ),该函数实际求解最近点对。/ d$ Y# S( y# p9 M5 R$ c
4 Z0 r) _, V. v1 S% T% k; `2 ]$ k
程序14-10 预处理及调用c l o s e 3 O7 g9 q5 H, a: i& L: o1 Y7 N . z9 q' V* [, I+ e4 X& Z" Z/ a) ]6 ybool closest(Point1 X[], int n, Point1& a, Point1& b, float& d)2 @3 u0 ]0 L2 W( E
5 U( C0 J% M _
{// 在n >= 2 个点中寻找最近点对: M; q! G8 G% I! {' I, e ^
" j( _; ^' F1 G& c+ T// 如果少于2个点,则返回f a l s e5 c4 s7 Y. k* y6 |1 l5 B
7 a g: x0 `8 V" M// 否则,在a 和b中返回距离最近的两个点- f' {# A- ?6 x5 c
* j4 \$ H, O1 uelse Z[f++] = Y; 9 p' z% M- Y+ F$ t! O # A) e7 n) U- A) M// 对以上两个部分进行求解# y0 ~, s. U- H1 {
9 y" B4 d) U5 f; O/ w" D
c l o s e ( X , Z , Y, l , m , a , b , d ) ; 3 ?6 R& F: n9 ^8 A+ d . n0 F# I+ Y! J& U2 I: [8 S+ yfloat dr;# [( e( d" X+ J I5 _0 I% M3 J( @
& a" e( ? `" v/ M. R0 @
Point1 ar, br;3 }) ~# M, J( v
( f9 C: Q5 ]. F0 p7 o: B
c l o s e ( X , Z , Y, m + 1 , r, a r, b r, d r ) ;# s, A: e/ y4 e. `) ]
. q' w& [$ x9 b, |% q// (a,b) 是两者中较近的点对 4 S* f. O K& G( C9 l8 D - P) n# w& Z J0 Y7 _" }if (dr < d) {a = ar; . z" M* w7 [: F+ O7 l ?( X) p) }' {% \" l0 P
b = br;6 P, {/ {- O o# n
/ a, i+ d/ ?+ K( ]
d = dr;} 8 w- F) t- ?3 B- ~1 p* h4 T9 K3 m$ |' |/ m$ H! e2 l, D6 h
M e r g e ( Z , Y,l,m,r);// 重构Y3 G. {3 J0 I2 `0 G) \0 p
: O. t Y8 e: r1 E$ c
/ /距离小于d的点放入Z / H4 P! [- l" j5 G! _& G+ Q 5 B6 T W* S: Z' p( yint k = l; // Z的游标 5 L1 P7 V+ b. R W% \8 w e( ^$ e* Wfor (i = l; i <= r; i++) % `) l. p I+ P% v" l( X( M! y. n$ p, B3 h
if (fabs(Y[m].x - Y.x) < d) Z[k++] = Y;$ s5 a$ G0 J8 R- F
0 V. g- X8 n: ?- k# n// 通过检查Z [ l : k - 1 ]中的所有点对,寻找较近的点对 6 @) M# t6 ?% B$ i5 {# J/ k' t, {. X6 a% \# Z( B: Y) C' A
for (i = l; i < k; i++){# P t6 k$ `+ }
4 v' M3 |4 e" z# N ?for (int j = i+1; j < k && Z[j].y - Z.y < d;, i* g+ q) M3 T3 n5 N& g$ F
, y9 F, L7 G3 R+ F+ ?, W( z
j + + ) { b4 q: O0 G, y' h8 }" {8 w1 [) y: i1 m/ Z8 V% v1 @" k6 f
float dp = dist(Z, Z[j]); : t7 d- k A+ [ c' A6 t' o- W$ l- Q( W+ t# y( c" C2 B
if (dp < d) {// 较近的点对 u' L: D' r4 s2 U$ P* I 3 y5 F1 m) ~. }2 U& `- T& W% [d = dp;# l4 O0 L" R9 d9 {6 i# b