, y3 k3 V. h; |! s# v* Q* s7 ffriend void main(); : c2 V+ @3 [' \, j; @3 x$ y5 { ; I) s# Q$ S8 u7 @; f/ I3 T* cp u b l i c :4 N" E. p& K. Y; N9 k8 r
$ O% Y' z" {3 q* _% H, ^- b M2 d
int operator<=(Point2 a) const 4 g) Y# s9 s' j5 D5 ~+ A' e % ], f3 i$ Y5 U' ]6 ~{return (y <= a.y);} 4 j5 Y! r; r' ?' n1 T/ ]- a8 r* ]) _
p r i v a t e :4 l( U5 L* F2 O
9 k; y5 p5 o! A5 rint p; // 数组X中相同点的索引 ' x, T+ F1 L( [. y& e/ L4 g8 V 2 |5 M, j+ \: o6 Rfloat x, y; // 点坐标 ; D d; j4 K |; j0 a+ t: R6 @+ [3 i0 [
} ;2 M3 Q/ N. m2 v& [' ?. h! v2 z
% M2 h0 m$ G9 G+ ~ g所输入的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中的对应点。/ O1 V/ F( N0 X1 H- c4 |, I
* H8 _' ^3 a! V3 f3 q确定了必要的数据结构之后,再来看看所要产生的代码。首先定义一个模板函数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类的友元。# ?9 p+ F3 ~7 L# z2 R- e/ e) ]5 u
% x8 b v4 g; Q/ Y( H1 H6 m* I0 Q
程序14-9 计算两点距离 , f( y! D+ t+ W3 K& b 2 {6 ~8 R9 c6 Stemplate<CLASS T>1 a. E4 J- f4 o
# I0 \/ u3 G0 Finline float dist(const T& u, const T& v)2 D1 t8 Y, O* O" H6 Y& i/ B
+ G9 c" I1 K, P. Z5 o; K
{ / /计算点u 和v之间的距离8 M) G `7 L) }- G3 u
6 c0 [; m: s/ K% F
float dx = u.x-v. x ; * N* l- d. c2 { ! h! o" r: j0 S& d$ hfloat dy = u.y-v. y ;! D k% L& O z/ M. W6 m* K
- L1 ^7 \% E- k2 k! k1 n1 @
return sqrt(dx * dx + dy * dy);+ C. z4 e$ t, q; {( x
* `1 G( x$ I( D2 H2 K} 6 s* w$ }. Z/ s $ L& I6 ]0 f9 o" k3 U如果点的数目少于两个,则函数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 ),该函数实际求解最近点对。' _5 r6 l C! _ N- A8 G# G
' Q+ t1 ?. j8 ], H程序14-10 预处理及调用c l o s e5 @* F2 f) O3 n1 ~' ~" ]' v3 Q+ B
8 f u) @* b, P6 i+ a9 s+ Ubool closest(Point1 X[], int n, Point1& a, Point1& b, float& d) ; R3 S w5 R# Y7 j# ^ a0 W; P, ` K; H9 ?
{// 在n >= 2 个点中寻找最近点对: r; f f, K' R) x! x+ S
+ g* \5 N) E$ [2 d5 O// 如果少于2个点,则返回f a l s e ) x- v7 R/ ]; n* F& W0 D; s ; y, b0 l: i- N& I// 否则,在a 和b中返回距离最近的两个点 ; O/ V! w' Y! K' M : F: @ X- A7 ~9 ?: Lif (n < 2) return false;* Z; G+ e+ z, Y3 ~2 A
# @. Z% W6 E$ Q4 I v
// 按x坐标排序 * g9 z" Z9 l! K' h% o% P# m2 i6 x2 `& f
M e r g e S o r t ( X , n ) ;3 V3 ?$ j* z6 O7 G
: _" x5 C* f, z6 z% i V% z: C! y+ e// 创建一个按y坐标排序的点数组 1 p5 {4 Z% ^* @- K, a' k* v% B1 l, L9 ]$ _' V. m, s. |" ^1 Z
Point2 *Y = new Point2 [n];5 y- ?' N( F; }
5 c+ U7 \) [# j! Ffor (int i = 0; i < n; i++) { 0 a8 Q6 ?4 Q5 r1 L. I+ N0 T, ? 1 W; b$ P3 z- V' S$ d: w// 将点i 从X 复制到Y 9 Q, N; ]! s' w2 \. o: `. j* k; O ' H4 N1 \3 W$ X( K' s0 V# RY.p = i;* s1 L5 M0 w! e7 k1 ?, o* V N
# J3 g m; R* l3 |1 c% @2 X& d
Y.x = X.x;6 l+ U+ I" ~; J! F% P7 \4 x |
5 j; P1 `1 \% zY.y = X.y;% t3 M, _: T. S) d9 x7 b& t
9 \* ]; {* z" L
} x, B9 a! k6 ?: c0 N& g! H9 b 2 z7 K& X& o: k* R/ r n2 cM e r g e S o r t ( Y,n); // 按y坐标排序3 I- x3 E8 p/ f$ U( L
5 m" i/ w8 }, P. ^9 ^
// 创建临时数组 1 d$ i1 L5 a- X* w @ 9 ]% s- j5 Z' |. l& ~0 FPoint2 *Z = new Point2 [n]; - q8 a6 ]2 L1 }" ? 3 E3 m4 n* u' j* X4 ]// 寻找最近点对1 E4 A0 t2 z( H
& {' H+ ~+ J+ [' N: w% h+ ]
c l o s e ( X , Y, Z , 0 , n - 1 , a , b , d ) ; 0 y+ x0 D$ ^- p. C& i3 i0 [. I) K- Z) \8 F4 _' w2 P# D
// 删除数组并返回 $ ?! d- W( b' F! q1 S' U I' m * G6 z5 m8 Y& O6 [delete [] Y; : u. F9 J8 R: ~$ `% _/ y 9 ^1 b5 h! t3 pdelete [] Z; 5 T' d R+ u7 e - f( @6 S! X* [( j8 wreturn true;; ~1 P" h, M" ~- B+ k' n9 ]
) E* M6 ~. e5 ~}. k1 i+ v6 _" \, A
i8 x8 ?/ B6 K2 [: z
程序1 4 - 11 计算最近点对 # j1 E& c8 ~0 T' Q( L$ A! ~: ^7 N8 R1 |, c; \+ W, Z
void close(Point1 X[], Point2 Y[], Point2 Z[], int l, int r, Point1& a, Point1& b, float& d)! P1 E& r7 L+ S7 m0 P
6 q8 f$ A: G# h
{//X[l:r] 按x坐标排序4 \) {8 N! s) z
2 l1 Z) g7 Z+ \/ M# ~//Y[l:r] 按y坐标排序 2 g- B4 @! v6 z* L6 r% G E7 f) b9 [' X4 k- A- c! b- g( Cif (r-l == 1) {// 两个点 2 J$ F5 S8 d. C4 w( z; g! ^4 j$ c5 |( H C" I
a = X[l]; 6 E w) i3 p2 f% N* z3 h1 Z$ C 5 A3 v9 ~. `2 l2 M# Ab = X[r]; ( Z4 g: y+ |+ }4 u, n8 E) D& S# n' H4 s, P
d = dist(X[l], X[r]);1 s, Q' _/ C+ D0 ~5 t3 A2 u" O
0 @/ z1 v, M* h/ f2 `$ |" R
r e t u r n ; } * ^5 Q# Z! y' J: n5 S3 t- n) X: ~% j3 L/ i
if (r-l == 2) {// 三个点& h7 I9 Y3 _- Z1 s
4 M! x6 g3 B x9 D) q3 p dint m = (l+r)/2; // X[l:m] 在A中,余下的在B中 # Q1 Q. P2 g' Q2 K3 ~ c1 A' P- a) H
// 在Z[l:m] 和Z [ m + 1 : r ]中创建按y排序的表 1 q6 V" {0 g2 W; z) M' M( ~6 U8 ~# ~* f. X& `: y
int f = l, // Z[l:m]的游标- t5 g. K M" C# S
0 O$ J; ] h8 Q* i, s; ug = m+1; // Z[m+1:r]的游标2 R: Y& e; V* ]6 D0 h, z* N
" J! T0 X: I- s& Z( f) Gfor (int i = l; i <= r; i++) 6 H1 L: I8 l. k. \ % Y2 k! {1 {. Q3 Jif (Y.p > m) Z[g++] = Y;" m6 h( t$ E5 v" ~* d! @
$ ~. u, [7 }+ `4 s: w. d: Z
else Z[f++] = Y;; y6 y2 G* @) h2 O: C
, E% M# V- t2 \+ ]3 P2 p0 U// 对以上两个部分进行求解1 d9 X. v# X1 Y4 B. j' x; s9 s
j! S+ ^3 f L1 S- k% [. n
c l o s e ( X , Z , Y, l , m , a , b , d ) ; # S6 O8 C0 i s: m0 m ( g% @# }' l' afloat dr; 9 D& w0 C! t# @' @: l 4 t% c( {2 D* z+ _. s6 mPoint1 ar, br; 0 o- X7 H% R. S0 d3 x% `7 Y$ a, ?0 _) Q$ `4 T
c l o s e ( X , Z , Y, m + 1 , r, a r, b r, d r ) ; 9 X& ~: ]) @7 s+ [8 g$ p: q7 U% {0 u' Y & k7 {4 M. h' g- i* T* h// (a,b) 是两者中较近的点对/ L F+ [- |8 i. u3 t( U: s# j
1 U1 g7 x1 @7 D' `& Y, Bif (dr < d) {a = ar; {1 m) r# U& R$ j' A, c: o' Y
- d9 V3 e _1 J- ^$ Kb = br; 6 t# c$ _ c# _$ p/ J/ }. B( c8 S5 s# Y. \, D
d = dr;}7 a9 O" d1 N6 V1 G8 r; M
) b) q) S$ V/ [, Q# M7 _
M e r g e ( Z , Y,l,m,r);// 重构Y 5 M& v) W8 L- o! ^( }# t! ? h" J( K b& |' q/ /距离小于d的点放入Z6 C! }0 ]+ m1 d7 ~
) m! ?7 a6 h) @9 z0 S
int k = l; // Z的游标1 J) ?% B( N' Z9 X/ O! O" r3 }
! z' ^* o8 I" m5 L1 y1 Y) [5 p$ |for (i = l; i <= r; i++) 5 @0 ]. v" y+ z4 K+ k, t! ` & e, \8 V7 g( M7 G* r9 |if (fabs(Y[m].x - Y.x) < d) Z[k++] = Y; + M3 c) T6 t% k& N( Y3 f0 N , h# \! l/ L; Q( I// 通过检查Z [ l : k - 1 ]中的所有点对,寻找较近的点对, |2 `) y. P5 i# o
1 z. J3 F& ] I& B/ `+ y
for (i = l; i < k; i++){ 8 j( k2 I& S \0 @ _* r6 U$ b) C& S
for (int j = i+1; j < k && Z[j].y - Z.y < d; v `- Y& T u, w9 W9 R: A
9 q; z' ]( a8 m& R" R {j + + ) {6 F& v* n" B; i/ @- }
N9 N( e3 ?8 o" H! X5 y
float dp = dist(Z, Z[j]);% ~: O# f2 t, L: I+ F
" n, s# c+ W- {5 ~
if (dp < d) {// 较近的点对" f* H5 A. X1 e, l5 o+ O" U" k
( a. U! ^, \/ O+ J
d = dp;$ g a- G$ L3 P
5 K- n1 [6 J0 p4 A- C P2 Aa = X[Z.p];6 m9 a1 p4 f) b( r0 H/ W8 P
) o% j. @0 v$ s* _; A这个递归式与归并排序的递归式完全一样,其结果为t (n) = (nl o gn)。另外,函数c l o s e s t还需耗时(nl o gn)来完成如下额外工作:对X进行排序,创建Y和Z,对Y进行排序。因此分而治之最近点对求解算法的时间复杂性为(nl o gn)。</P>