; ] h. E- M0 {# Tfriend void main(); 9 S6 x' c# d* P6 r# H" s$ M8 E9 g
p u b l i c : 8 i; V2 f3 T5 r4 g, w* M+ u# Y* H3 n3 N
int operator<=(Point1 a) const# g/ G; d& q) Z$ o' K
/ ]$ |6 \# @2 l' W6 [% dp r i v a t e :$ S+ f9 q+ b; q
* i* O! ^; V4 b7 _
int ID; // 点的编号 / R$ e1 }3 r! h; }; i! {8 s: J1 ^ # G6 R- g9 @- y& F+ g8 zfloat x, y; // 点坐标! {# Q! C$ P& @) g: M8 W
: q, N3 X) e7 P. c* h b! \} ; 1 d9 N7 m6 `# g8 a 2 g' P5 K; a7 U" s. rclass Point2 { % J5 ?. M A0 I ! o7 V. m6 i/ A' c' X% \* Yfriend float dist(const Point2&, const Point2&);. V8 j9 m( [& _; m# z# v3 w: O
8 b h; b" l0 j" U, V4 c# sfriend void close(Point1 *, Point2 *, Point2 *, int, int, Point1&, Point1&, float&);" i( z! h# Y& @+ x
% Z4 X4 y" H+ D$ k [: cfriend bool closest(Point1 *, int, Point1&, Point1&, float&); ; @1 h: O+ g1 [$ I& p& W2 k* u; Y: x" R
friend void main(); 4 H/ p8 r% N; b/ D. ~5 J9 @& b1 U/ e: B8 p- T! B
p u b l i c :- E g! }! W" w$ a
1 n1 T+ s! r- \3 @& I$ N8 Z; }
int operator<=(Point2 a) const 8 d1 e, e4 x( |9 R3 v$ z ' m! u+ L- v3 y& K/ q j{return (y <= a.y);} ; N5 S7 Q, ]8 J4 l( S, G9 X1 q# @: ^1 K% F
p r i v a t e : 8 D5 L$ |/ l' r) G! U, ~, q8 w5 h: c k$ O$ D5 x5 `
int p; // 数组X中相同点的索引 " M, Z% u/ t% g3 v7 w' ?# k% @ 1 _. z' l" g) Z. T6 v' X9 T5 ufloat x, y; // 点坐标- K/ `0 |% z6 p5 g* o! i1 F9 Y v
* K7 W/ o& a0 M3 a} ; 7 f& A- U( C; Y ^3 B/ ? N P! t: b5 E( H( A
所输入的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中的对应点。# x% h% }' O& n7 P
" X6 ]$ s: O! S% A! y
确定了必要的数据结构之后,再来看看所要产生的代码。首先定义一个模板函数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 b! C! R' a- M& g% y% \3 W3 d& w
9 G# n6 v8 j3 _- Z4 s; J
程序14-9 计算两点距离3 p1 A9 g# e1 h2 J
* Z) a& G h' {4 l. Ztemplate<CLASS T> * }4 Y b! ]. s0 V4 s3 E & ]/ o2 M" |) v+ G& j- }inline float dist(const T& u, const T& v)6 }4 D9 Q9 ^: C# l5 f! A
2 j# P3 @$ o6 K8 Z; c{ / /计算点u 和v之间的距离. V& L* W+ m1 B _9 M
; Z5 i# B2 e ?float dx = u.x-v. x ; / ]+ D- ~5 ?& a3 P% ]; w( i$ ? 8 @, r6 b: r1 Mfloat dy = u.y-v. y ; 1 W% D w7 P7 {! X3 H4 F- U a( s# [6 d0 _2 u+ L: R9 ? g* y$ X
return sqrt(dx * dx + dy * dy); . d" I# s* D1 c B; Q+ T, l , W0 D! G8 e: g, A& j}* [" E# x( G, Q0 I: \
8 N) k- j$ `+ _* b/ N$ I+ 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 ),该函数实际求解最近点对。$ w: d0 ]6 x: j- B
& f+ k/ w9 z u' l6 ]0 Q( z* N
程序14-10 预处理及调用c l o s e 4 {9 @1 u: v! ?" s( p ( Y( r4 X( ?" n8 p$ dbool closest(Point1 X[], int n, Point1& a, Point1& b, float& d) 6 h( v1 {* w3 A# c1 l3 S0 C+ l* J - F3 e5 B: c" W, @; r: K* o2 c{// 在n >= 2 个点中寻找最近点对 8 g" `( n9 `4 s7 K4 G: |* r! D- d4 }3 H: S# b, v
// 如果少于2个点,则返回f a l s e 7 b2 G; @) y% t o # @' e2 _' K/ z* A; ]/ i# c// 否则,在a 和b中返回距离最近的两个点 + m* Z+ U, S0 P4 P' O; E( `. w! s# ~5 V, L9 u7 x
if (n < 2) return false; " `: P* X K5 D/ g4 T( O3 Y3 |9 w6 @& a
// 按x坐标排序/ T, F$ I% V9 z/ V S
) |1 P! ~& p7 O% `5 s8 h, OM e r g e S o r t ( X , n ) ;9 H( M( {: ^3 F; ]% m
/ @! ^7 u# ^0 Q1 j4 d7 p
// 创建一个按y坐标排序的点数组 1 x! b6 k' x% p; i1 D! H, L7 k 0 j% I: l3 {) }/ D! @Point2 *Y = new Point2 [n];: W, X. u" x: ]& ?9 D; l3 W" ?* I/ A0 f
7 w- H, D- r, L9 V
for (int i = 0; i < n; i++) {$ q2 v7 }: f1 l6 [& @1 L5 W
/ q& s X$ s; S1 }, E- t" k( _
// 将点i 从X 复制到Y8 ]% t" g5 n0 z3 F3 n! x8 \' [
& W2 `( s5 R3 U$ @7 ?
Y.p = i; $ ^, g9 x" g, B6 R2 b6 A2 \' O; n. e; A0 I5 u/ d/ A5 _( v
Y.x = X.x; 0 ^3 p c4 Q+ s4 ~; S# P/ J4 k7 f* W , U7 {' p4 w) ^9 `+ g, J, h6 YY.y = X.y; ) q3 @* I0 ~( m! _2 h% R % X; y6 d6 C4 H$ c} - N- i" e, Y \& P* o. a 9 z# W( O- D5 V# @! a0 XM e r g e S o r t ( Y,n); // 按y坐标排序2 d% v* l7 e# ~- \5 R) I# }3 @
/ ~! k, l+ j& w/ D// 创建临时数组) C* l8 `* M- a+ @
9 ~5 ^( g+ ]$ ]! V% [( H% hPoint2 *Z = new Point2 [n]; ' k0 {9 ?+ z: q' |- H! N 4 X( V! t, G) k" Y# @// 寻找最近点对 5 l' C( D5 g3 F K3 f/ g$ H1 j) @, I8 L: [0 p
c l o s e ( X , Y, Z , 0 , n - 1 , a , b , d ) ; - M+ }2 j' _9 m5 ~$ ] ) ]9 z7 [& _' I& M/ A// 删除数组并返回6 W5 A1 g& O6 S3 _9 @
3 E' h& |/ P/ V( v" E9 Q8 \
delete [] Y; ; N, M) r. u" V2 \( P 7 L; V8 F& S3 Z0 h( ^/ i3 H/ Adelete [] Z;* O8 a( h6 [3 o
5 Y" \- Y" o& ^2 M- l2 g& f$ t* vreturn true; M# u4 k2 w$ W 7 Q. D3 r* W# O$ \5 m}" U' I# y) H# e! j2 S1 } ?
% |; K6 M& K, D: b* {! |6 E
程序1 4 - 11 计算最近点对 % c) ~5 U. o3 S8 U 3 x3 v! @( ?! A7 d4 Uvoid close(Point1 X[], Point2 Y[], Point2 Z[], int l, int r, Point1& a, Point1& b, float& d) 6 g) t( Q, i& _$ m : R3 V. H( N: X1 C& j: I6 k{//X[l:r] 按x坐标排序4 V/ z k8 G/ m! e
7 z5 P' h+ x' x7 t//Y[l:r] 按y坐标排序 ( n6 `4 y8 ^2 A- } R5 l% n' f+ D9 Q% d3 b' k
if (r-l == 1) {// 两个点. O8 B* R; b, t5 O* n9 C
6 U& L; v6 q; S8 k* @2 na = X[l]; " a" b e5 X- l! r6 O5 y7 P7 ]4 p; F7 a
b = X[r];$ B, p V$ ?. O' e
+ F. f0 Z9 m% pd = dist(X[l], X[r]);5 I. m0 F; k* l% q" T# T9 L
) ^/ f5 N' v1 Cr e t u r n ; } % W, H7 w4 P4 V0 P$ ` 2 R6 X- e( j' {, D; }! {if (r-l == 2) {// 三个点 / f* V% M: s" J9 l k+ _ ; x* s0 Z6 y. U* N Q* `// 计算所有点对之间的距离; I8 I9 f" e7 Y& a' X1 Q
2 J8 u: M6 w6 {+ g3 x. v
float d1 = dist(X[l], X[l+1]); % e/ `& k c% ^' Z, {8 R. h" e" c- P$ {0 M! ]
float d2 = dist(X[l+1], X[r]); $ W! E! Y6 d: O. j) @: v' a: d3 d
float d3 = dist(X[l], X[r]);. v/ p% P4 q" |* M5 _$ \
" I0 |6 k- x$ V, ^
// 寻找最近点对 9 c( Y' T8 Q6 R $ e" t# o4 E' Y0 `8 Mif (d1 <= d2 && d1 <= d3) {3 v9 T0 g" }. f- S3 [! Z
; E- I: T! W! i5 e+ K) H+ v1 ?/ }$ p! }a = X[l];. l' f. o# G7 T% ~9 y
7 w+ @, l3 k8 Q. G
b = X[l+1];) V6 J5 R; g1 Q
) ~9 g# M4 p# i' m/ m; Z; W2 r
d = d1; & l1 M% \: B) ?* K- x, k8 P$ D$ f3 V
r e t u r n ; }0 U) F- V- [7 R; Q+ m# h' d/ m
+ f9 a: k* t) U/ ]! G1 p' @$ F( N
if (d2 <= d3) {a = X[l+1]; $ ?" c8 d3 @5 U" ]+ V2 A * E8 [ J7 H1 H2 |5 M" rb = X[r];% U2 i9 _1 H+ }* Y3 M$ k, E
, G. i# D$ R3 s& s
d = d2;} ' ~. b' B8 I! u9 f# t1 Y) h* n9 r, a9 h9 V! K# |" S3 |
else {a = X[l];! y+ I: s( N3 L/ p- Z4 g6 q, Z7 \, ^
! A1 ?3 {- P3 a7 T; s8 Kb = X[r]; 9 u! C/ D: x; ^. x 3 @! a# w9 V" z! B- Y$ |d = d3;} f# ?1 U4 N; ?' [( C- { \1 A' p$ o: c/ u+ b4 T' o. J5 M, R7 g
r e t u r n ; }9 ~6 [! f* m: |
5 F" ]3 M9 E3 {* |// 在Z[l:m] 和Z [ m + 1 : r ]中创建按y排序的表 + N2 o W+ J8 n& Z' l, @2 U/ V& k# {! F6 a
int f = l, // Z[l:m]的游标9 x. t' [- ?+ D L: n, R0 E
2 { ~% `" P% }( ?6 Y/ n6 Q% |( H
g = m+1; // Z[m+1:r]的游标 8 x/ x: p; e# H6 c; T 4 v/ X2 j* S; L3 k3 e* [for (int i = l; i <= r; i++)% w4 s2 K3 k( b# |% C3 l3 E
; F j# Z0 _0 N5 O
if (Y.p > m) Z[g++] = Y; $ Z, M2 G% V) n4 @/ U4 e7 A7 ^1 C0 b( l# S2 f3 e
else Z[f++] = Y;( \" i6 `- ^# c' n
6 \ f& K3 ~2 p: n8 P# u0 f// 对以上两个部分进行求解1 e# J' }* h/ f
4 H# i! Z# {( l" `. d; q; U
c l o s e ( X , Z , Y, l , m , a , b , d ) ; 8 [1 S% o7 g7 }, W4 E9 r( P8 q* P1 W9 J5 s% U, k4 n1 a$ S
float dr; / u7 @7 d7 x" v8 Z7 }/ [ % s- _/ R: e6 j: W/ rPoint1 ar, br;5 @" \1 f* T' v# N4 F/ r% n, l) R
, I3 p" u2 n0 t( Q- Qc l o s e ( X , Z , Y, m + 1 , r, a r, b r, d r ) ; - E& c$ I$ I5 b# c$ q; e" ~) z8 t' a+ _- b$ R! ?
// (a,b) 是两者中较近的点对 . E: n/ v7 w$ S5 ~5 F ; q% ^$ e1 l3 k9 Vif (dr < d) {a = ar;& p& T1 n' x E" s q/ s$ _
$ z ` }; q* f/ g1 a2 N( A1 Vd = dr;} 4 V6 M M9 L6 E% z2 X* e" |: v6 O' U0 o
M e r g e ( Z , Y,l,m,r);// 重构Y. l4 a! |" N$ p e( {+ L. U
. O4 u" ^# {3 n# U. x. v3 b& q6 i
/ /距离小于d的点放入Z 9 }1 S* [; ~5 @ $ ]8 r, H0 n, J1 Iint k = l; // Z的游标7 n' O9 \: U: s( K/ z5 q
$ n- ?! m$ u$ b" i. Lfor (i = l; i <= r; i++)9 n2 d% M5 r/ O
0 S, b( z/ N# m2 U! S
if (fabs(Y[m].x - Y.x) < d) Z[k++] = Y; % _6 E8 N" ^ S( O& I" T1 ^3 y$ [/ }1 f& X) ?/ g
// 通过检查Z [ l : k - 1 ]中的所有点对,寻找较近的点对) X6 f5 q) N0 C0 o7 y