2 R6 x j; F; X, x" B+ T3 yp u b l i c : 1 D Q& i9 o% N9 n" @1 X& c7 K- a, z" E n
int operator<=(Point1 a) const % v9 z9 v% I! r( k3 D/ h9 P( w0 `+ G. N# r, E5 ]- t; I. X
{return (x <= a.x);} / H0 y7 e. P2 o& j4 f! K' d, B" d! \+ ~8 W& v
p r i v a t e :: J' a9 T# B% u# |8 D/ ]: d
' S. |* W. S" f/ xfriend void main(); ' Y+ q; c' m) T( |. C# ^ ! e8 p5 T# Q8 n- sp u b l i c :5 k K2 k' s* e
: E( D! \6 R# [
int operator<=(Point2 a) const3 s- [- S/ _8 q
' e2 ?7 B# @2 Q# A0 y% O+ b8 H{return (y <= a.y);} " t# ~" i$ |$ j$ w$ O# o; W - f4 _. ^8 y) u) V' _3 fp r i v a t e :# Y) z0 K V+ C+ V8 W6 @
! F, c2 X) p3 @" v
int p; // 数组X中相同点的索引 5 Y! {$ G& I1 {; D, D/ s4 `. N" @3 `
float x, y; // 点坐标 ' P+ ~ Q- l2 x. V 7 C* k" o2 Q3 Q0 h& [1 H} ; 2 f, M I! R J t# v - ?$ Y/ H, |) _5 U所输入的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中的对应点。 * r; e7 a8 f: E7 X% K) t& F' E0 N, v1 R5 g
确定了必要的数据结构之后,再来看看所要产生的代码。首先定义一个模板函数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类的友元。 : ~0 s; [ M5 l5 ]; E& c# ^# q) u& r: Y% D
程序14-9 计算两点距离 X& F( A( V C& \: ^- J! W: k3 y7 L
template<CLASS T> ; l! c5 ~$ k" _2 ^% Z9 n 6 w4 O9 D; P* w3 t* `inline float dist(const T& u, const T& v), C# o8 r$ f5 @; t# O
# ^+ ]: `8 d& o3 A7 ?% v. S{ / /计算点u 和v之间的距离 * |4 c$ j M$ M' y; L) L, p0 I9 E( i7 p' ^9 f
float dx = u.x-v. x ; $ B4 }' r6 w' Q4 b; i5 m( B" s " z, P1 |, ]; r: R& cfloat dy = u.y-v. y ; 6 i# b+ O7 L2 ?( N: [ y2 B) U 5 s8 X: O( q2 z( @return sqrt(dx * dx + dy * dy);6 M9 X* G' d6 X# e* _: b
% |3 |+ k! {% \# B} & b! [( n" q6 @" b ) ~3 j. z5 H2 I& x1 |9 z如果点的数目少于两个,则函数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 ),该函数实际求解最近点对。1 A4 V/ X" a) h3 B7 ^; B* W
+ ~0 E$ N& ` J/ B程序14-10 预处理及调用c l o s e( [. T: K/ z3 `7 K/ q
; L1 ?8 n5 R% A5 ~' ?/ J
bool closest(Point1 X[], int n, Point1& a, Point1& b, float& d)0 |% O0 f% l0 w5 ]' H
+ x# W, d" Q: v{// 在n >= 2 个点中寻找最近点对 6 H: [3 R9 r( Q3 X' M+ U ' {! r2 w( i1 v$ S) i3 s. E// 如果少于2个点,则返回f a l s e 9 b$ V4 G# x2 ?: |9 q' B- z8 ~# p* |$ T. T" b7 s
// 否则,在a 和b中返回距离最近的两个点8 @2 U: Y. \9 i7 Q/ V6 ?
" g2 T5 A- Z; m$ I
if (n < 2) return false; & E7 W$ L) c G7 @( _# m* p& [% W2 n, r+ W+ w' ^, q
// 按x坐标排序2 q. \- X2 x; p
3 @" v9 T* o Y0 J" z5 }4 NM e r g e S o r t ( X , n ) ;: A% e+ i0 b, d8 Q
7 u! g; N9 ~3 U! ?: W6 Z// 创建一个按y坐标排序的点数组" L! ~. k- Q0 s' [! U
9 `( R+ G8 E& |* C1 tY.y = X.y;7 ], _# `9 [* C2 y* |4 C
: R3 E$ P5 D: T$ V- A4 j
}6 m2 N+ [9 M! g- O
! ?7 [6 M1 n* s* }* e% j
M e r g e S o r t ( Y,n); // 按y坐标排序 ; L; u" M2 T" N6 P c) V1 k! t # B9 [ ^, l1 x// 创建临时数组" C: I0 s# f$ h% \9 {! p) Y& X
" H, ]6 z2 {! q8 T
Point2 *Z = new Point2 [n]; ) J4 T1 j8 u# P* I - @1 Y! ]9 l5 H V. v// 寻找最近点对 0 N+ p0 w/ B! T: g }: X5 g2 F( q0 m: W: u9 W( `8 i
c l o s e ( X , Y, Z , 0 , n - 1 , a , b , d ) ; " J6 y, Q0 O8 e' i6 [4 X0 Y4 J$ o8 M7 k & B w5 q9 S s) b4 c// 删除数组并返回 $ A) \! i, L. U# q7 ] |+ I% z* \" H
delete [] Y;% U1 a, b8 X( v) d% J; o b
x1 I) `8 P7 N6 z
delete [] Z; 9 I+ Q; d4 A0 k. l. d : j( C1 Q2 h. l8 I# y& p) u6 Nreturn true; & v: b& g- I9 H$ N, [' M: n# i9 ?' O+ D
}7 u7 _! v# {: z; r; \1 q' i, o7 Z" ^$ |
4 n2 }( ^ M4 S; o, T程序1 4 - 11 计算最近点对' G M! y! l$ b2 H* X1 J
. s. y' X+ M3 z# n) i1 ^& ovoid close(Point1 X[], Point2 Y[], Point2 Z[], int l, int r, Point1& a, Point1& b, float& d)% o6 E, T& d: f; E/ L N" t9 x
3 j7 E Z3 Q0 ~5 c1 E' p. x
{//X[l:r] 按x坐标排序 4 ]0 b1 F m/ y " R' ^9 O2 S- e* i* E- ?9 v//Y[l:r] 按y坐标排序 7 C$ X# H0 C( j) _) a+ Y5 l. _% g, {+ c
if (r-l == 1) {// 两个点. O, x8 q6 k' b( w1 I9 h/ j( Q7 X
* E% [" G1 K1 a: G( P$ l9 P
a = X[l]; 8 i: H' z; d1 `+ m( L% ^$ x$ ^7 G- ]# I7 G) d, F
b = X[r]; ( d$ ]) |" h0 j, B" d; r7 t$ d7 P3 O8 P: H
d = dist(X[l], X[r]); 2 D2 @ u. T* P$ ^ [1 P- y" {3 F# H) ?' M' Vr e t u r n ; }) s' B% t; P& q6 ]; L' i
' T; @$ ^2 C/ R
if (r-l == 2) {// 三个点 5 z% N$ V& L7 N; d ' K" o6 T5 d8 ~// 计算所有点对之间的距离0 C- q# o# X j3 A2 d
: h' v. l+ j) R2 D" pfloat d1 = dist(X[l], X[l+1]);% w+ v6 F; H& }- e8 }# \" U. h
6 w6 A4 _, w& P9 y
float d2 = dist(X[l+1], X[r]);1 g7 s6 _; E& v; Y% a% V
! z( @3 l6 F5 S, C W9 ~float d3 = dist(X[l], X[r]); y6 ?8 M! k9 x6 m' {* U6 ^4 E
( r, V4 f; C: s5 r; t' ?+ Z
// 寻找最近点对 5 u' @' B* R7 W4 L+ x+ F- d, h! U' {' Q
if (d1 <= d2 && d1 <= d3) { ( I# i* Q. S. `9 ~$ v. m) N) u) [, _ U% C ?$ B- ?
a = X[l]; ) _& a' c) E& `' P; }! e y - T: Z* l3 u4 p! {% o8 zb = X[l+1];1 N) J' H& i Z3 V4 z5 P+ _
5 r4 ^- U2 z I' K+ F9 J; e
d = d1; ' Q- }5 p9 J8 r$ g; p4 {- ~; a: J 5 G) K* d3 z" O" s0 Wr e t u r n ; } . u& g0 j4 D" v- B" W( h 9 ^% M9 {0 ]% e1 a* z* E. qif (d2 <= d3) {a = X[l+1]; 7 ?1 I* z d; m; y4 ?. s1 @ 8 b3 ~1 C4 j7 Wb = X[r]; 9 O6 L+ Y0 [, [8 Y% I: p) _; i. E: I l: H# S
d = d2;} . c9 T/ S) B1 o9 k- A: ~4 H1 W# D2 J
else {a = X[l]; 1 L) i' V' L Q! E2 g! K0 M! F 7 e p7 `6 d; Y7 c" ub = X[r]; ; q% Z. {( U) G- }7 d3 P, V* U5 Q; N( `
d = d3;}3 L7 T- E, }" T: Z% v
1 D1 {8 X' ]. R2 V( r' lr e t u r n ; }; F/ P) A0 [4 a$ t- f \+ Q
9 h, ]" B+ K0 ^
/ /多于三个点,划分为两部分 : h' i; I6 z; u6 P. W) \6 M1 V 3 x5 _- e+ U vint m = (l+r)/2; // X[l:m] 在A中,余下的在B中 2 T+ H0 ?& A* ^! U # i3 N$ p! m1 i// 在Z[l:m] 和Z [ m + 1 : r ]中创建按y排序的表6 X# F/ U7 ]# [: r
# V) t* j( ^% B5 p+ J5 L" e) o
int f = l, // Z[l:m]的游标 " u- M& I3 [, h& H( m' J* `5 g$ b9 R* [2 F& z/ S- d: a5 l; |
g = m+1; // Z[m+1:r]的游标 * C5 [# C4 ^! {/ C3 W& |; R7 }" Z: ~/ l
for (int i = l; i <= r; i++) * h# T) d$ K, [# q5 H9 X % c8 D7 f; S% r4 A4 i7 l/ uif (Y.p > m) Z[g++] = Y;, w' a- {: G2 R7 e3 j6 U$ j
& H5 Q" ?5 L& V0 ~
else Z[f++] = Y; ( y+ H- V1 j, O4 E# ~* Z" v 7 q' L, g6 v0 Z1 K// 对以上两个部分进行求解: u/ R F4 F% d9 H5 i( }* Y
" u( {/ i- [& V" U+ b1 v- wc l o s e ( X , Z , Y, l , m , a , b , d ) ;7 _4 H j/ I( X6 r
& s; v5 J7 H- f0 |: @! W: z% Hc l o s e ( X , Z , Y, m + 1 , r, a r, b r, d r ) ; 6 s8 G7 Z9 W$ z; i % d, E5 K# K* a4 e# j- |// (a,b) 是两者中较近的点对; j3 y# a5 l6 y# `2 c( \
1 v$ r, h: n, _( }& A- P2 A
if (dr < d) {a = ar;; s0 P( B( K! j. H3 B# o
3 |4 A* I' l0 ?, Q+ {) vb = br; $ R! N( Q5 B t; I5 j0 t9 X2 B9 t' r+ C
d = dr;} : L; |7 q& e& {% C, h; O3 W, F4 s+ q7 y% m. e8 W0 X
M e r g e ( Z , Y,l,m,r);// 重构Y 9 m- Y# [0 r/ ^% V9 L7 z6 p/ E
/ /距离小于d的点放入Z * V2 o" h+ Q4 y2 A P6 u4 n3 S# o" I: O, o+ F( b: l3 T
int k = l; // Z的游标* [1 _: \" e' O U0 a1 V
$ I) b/ k; v# K# zfor (i = l; i <= r; i++)* y7 l( Y6 ~- x5 j1 }6 G# e