Nội dung Text: Thuật toán Algorithms (Phần 38)

CLOSEST POINT PROBLEMS 363
I I
I
/&
I ‘1. l L
J
\ M
A vertical dividing line just to the right of F has eight points to the left, eight
points to the right. The closest pair on the left half is AC (or AO), the closest
pair on the right is JM. If we have the points sorted on y, then the closest pair
which is split by the line is found by checking the pairs HI, CI, FK, which is
the closest pair in the whole point set, and finally EK.
Though this algorithm is simply stated, some care is required to imple-
ment it efficiently: for example, it would be too expensive to sort the points
on y within our recursive subroutine. We’ve seen several algorithms with a
running time described by the recurrence T(N) = 2T(N/2)+N, which implies
that T(N) is proportional to N log N; if we were to do the full sort on y, then
the recurrence would become T(N) = 2T(N/2) + Nlog N, and it turns out
that this implies that T(N) is proportional to N log2 N. To avoid this, we
need to avoid the sort of y.
The solution to this problem is simple, but subtle. The mergesort method
from Chapter 12 is based on dividing the elements to be sorted exactly as
the points are divided above. We have two problems to solve and the same
general method to solve them, so we may as well solve them simultaneously!
Specifically, we’ll write one recursive routine that both sorts on y and finds the
closest pair. It will do so by splitting the point set in half, then calling itself
recursively to sort the two halves on y and find the closest pair in each half,

364 CHAPTER 28
then merging to complete the sort on y and applying the procedure above to
complete the closest pair computation. In this way, we avoid the cost of doing
an extra y sort by intermixing the data movement required for the sort with
the data movement required for the closest pair computation.
For the y sort, the split in half could be done in any way, but for
the closest pair computation, it’s required that the points in one half all
have smaller z coordinates than the points in the other half. This is easily
accomplished by sorting on x before doing the division. In fact, we may as
well use the same routine to sort on z! Once this general plan is accepted,
the implementation is not difficult to understand.
As mentioned above, the implementation will use the recursive sort and
merge procedures of Chapter 12. The first step is to modify the list structures
to hold points instead of keys, and to modify merge to check a global variable
pass to decide how to do its comparison. If pass=l, the comparison should
be done using the x coordinates of the two points; if pass=2 we do the y
coordinates of the two points. The dummy node z which appears at the
end of all lists will contain a “sentinel” point with artificially high z and y
coordinates.
The next step is to modify the recursive sort of Chapter 12 also to do the
closest-point computation when pass=2. This is done by replacing the line
containing the call to merge and the recursive calls to sort in that program
by the following code:
if pass=2 then middle:=bt.p.x;
c:=merge(sort(a, N div 2), sort(b, N-(N div 2)));
sort:=c;
if pass=2 then
begin
a:=c; pl :=zt.p; p2:=zt.p; p3:=zt.p; p4:=zf.p;
repeat
if abs(at.p.x-middle)

CLOSEST POINT PROBLEMS 365
If pass=1, this is straight mergesort: it returns a linked list containing the
points sorted on their z coordinates (because of the change to merge). The
magic of this implementation comes when pass=2. The program not only sorts
on y but also completes the closest-point computation, as described in detail
below. The procedure check simply checks whether the distance between the
two points given as arguments is less than the global variable min. If so, it
resets min to that distance and saves the points in the global variables cpl
and cp2. Thus, the global min always contains the distance between cpl and
cp2, the closest pair found so far.
First, we sort on x, then we sort on y and find the closest pair by invoking
sort as follows:
new(z); zf.next:=z;
zf.p.x:=maxint; zt.p.y:=maxint;
new(h); ht.next:=readlist;
min:=maxint;
pass:=l; hf.next:=sort(hf.next, N);
pass:=2; hf.next:=sort(hf.next, N);
After these calls, the closest pair of points is found in the global variables cpl
and cp2 which are managed by the check “find the minimum” procedure.
The crux of the implementation is the operation of sort when pass=2.
Before the recursive calls the points are sorted on x: this ordering is used to
divide the points in half and to find the x coordinate of the dividing line. Ajter
the recursive calls the points are sorted on y and the distance between every
pair of points in each half is known to be greater than min. The ordering on
y is used to scan the points near the dividing line; the value of min is used to
limit the number of points to be tested. Each point within a distance of min
of the dividing line is checked against each of the previous four points found
within a distance of min of the dividing line. This is guaranteed to find any
pair of points closer together than min with one member of the pair on either
side of the dividing line. This is an amusing geometric fact which the reader
may wish to check. (We know that points which fall on the same side of the
dividing line are spaced by at least min, so the number of points falling in any
circle of radius min is limited.)
It is interesting to examine the order in which the various vertical dividing
lines are tried in this algorithm. This can be described with the aid of the
following binary tree:

CHAPTER 28
G OA DE CH FI KB PN JM L
Each node in this tree represents a vertical line dividing the points in the left
and right subtree. The nodes are numbered in the order in which the vertical
lines are tried in the algorithm. Thus, first the line between G and 0 is tried
and the pair GO is retained as the closest so far. Then the line between A and
D is tried, but A and D are too far apart to change min. Then the line between
0 and A is tried and the pairs GD G-4 and OA all are successively closer pairs.
It happens for this example that no closer pairs are found until FK, which is
the last pair checked for the last dividing line tried. This diagram reflects the
difference between top-down and bottom-up mergesort. A bottom-up version
of the closest-pair problem can be developed in the same way as for mergesort,
which would be described by a tree like the one above, numbered left to right
and bottom to top.
The general approach that we’ve used for the closest-pair problem can
be used to solve other geometric problems. For example, another problem of
interest is the all-nearest-neighbors problem: for each point we want to find
the point nearest to it. This problem can be solved using a program like the
one above with extra processing along the dividing line to find, for each point,
whether there is a point on the other side closer than its closest point on its
own side. Again, the “free” y sort is helpful for this computation.
Voronoi Diagrams
The set of all points closer to a given point in a point set than to all other points
in the set is an interesting geometric structure called the Voronoi polygon for
the point. The union of all the Voronoi polygons for a point set is called its
Voronoi diagram. This is the ultimate in closest-point computations: we’ll see
that most of the problems involving distances between points that we face
have natural and interesting solutions based on the Voronoi diagram. The
diagram for our sample point set is comprised of the thick lines in the diagram
below:

CLOSEST POINT PROBLEMS 367
Basically, the Voronoi polygon for a point is made up of the perpendicular
bisectors separating the point from those points closest to it. The actual
definition is the other way around: the Voronoi polygon is defined to be the
set of all points in the plane closer to the given point than to any other point
in the point set, and the points “closest to” a point are defined to be those that
lead to edges on the Voronoi polygon. The dual of the Voronoi diagram makes
this correspondence explicit: in the dual, a line is drawn between each point
and all the points “closest to” it. Put another way, x and y are connected in
the Voronoi dual if their Voronoi polygons have an edge in common. The dual
for our example is comprised of the thin dotted lines in the above diagram.
The Voronoi diagram and its dual have many properties that lead to
efficient algorithms for closest-point problems. The property that makes these
algorithms efficient is t,hat the number of lines in both the diagram and the
dual is proportional to a small constant times N. For example, the line
connecting the closest pair of points must be in the dual, so the problem of
the previous section can be solved by computing the dual and then simply
finding the minimum length line among the lines in the dual. Similarly, the
line connecting each point to its nearest neighbor must be in the dual, so the
all-nearest-neighbors problem reduces directly to finding the dual. The convex
hull of the point set is part of the dual, so computing the Voronoi dual is yet

CHAPTER 28
another convex hull algorithm. We’ll see yet another example in Chapter 31
of a problem which can be efficiently solved by first finding the Voronoi dual.
The defining property of the Voronoi diagram means that it can be used
to solve the nearest-neighbor problem: to identify the nearest neighbor in a
point set to a given point, we need only find out which Voronoi polygon the
point falls in. It is possible to organize the Voronoi polygons in a structure
like a 2D tree to allow this search to be done efficiently.
The Voronoi diagram can be computed using an algorithm with the same
general structure as the closest-point algorithm above. The points are first
sorted on their x coordinate. Then that ordering is used to split the points in
half, leading to two recursive calls to find the Voronoi diagram of the point
set for each half. At the same time, the points are sorted on y; finally, the
two Voronoi diagrams for the two halves are merged together. As before, the
merging together (done with pass=2) can make use of the fact that the points
are sorted on x before the recursive calls and that they are sorted on y and the
Voronoi diagrams for the two halves have been built after the recursive calls.
However, even with these aids, it is quite a complicated task, and presentation
of a full implementation would be beyond the scope of this book.
The Voronoi diagram is certainly the natural structure for closest-point
problems, and understanding the characteristics of a problem in terms of
the Voronoi diagram or its dual is certainly a worthwhile exercise. However,
for many particular problems, a direct implementation based on the general
schema given in this chapter may be suitable. This is powerful enough to
compute the Voronoi diagram, so it is powerful enough for algorithms based
on the Voronoi diagram, and it may admit to simpler, more efficient code, just
as we saw for the closest-nair nroblem.

369
Exercises
1. Write programs to solve the nearest-neighbor problem, first using the grid
method, then using 2D trees.
2. Describe what happens when the closest-pair procedure is used on a set
of points that fall on the same horizontal line, equally spaced.
3. Describe what happens when the closest-pair procedure is used on a set
of points that fall on the same vertical line, equally spaced.
4. Give an algorithm that, given a set of 2N points, half with positive z
coordinates, half with negative x coordinates, finds the closest pair with
one member of the pair in each half.
5. Give the successive pairs of points assigned to cpl and cp2 when the
program in the text is run on the example points, but with A removed.
6. Test the effectiveness of making min global by comparing the performance
of the implementation given to a purely recursive implementation for
some large random point set.
7. Give an algorithm for finding the closest pair from a set of lines.
8. Draw the Voronoi diagram and its dual for the points A B C D E F from
the sample point set.
9. Give a “brute-force” method (which might require time proportional to
N2) for computing the Voronoi diagram.
10. Write a program that uses the same recursive structure as the closest-pair
implementation given in the text to find the convex hull of a set of points.

370
SOURCES for Geometric Algorithms
Much of the material described in this section has actually been developed
quite recently, so there are many fewer available references than for older,
more central areas such as sorting or mathematical algorithms. Many of the
problems and solutions that we’ve discussed were presented by M. Shamos in
1975. Shamos’ manuscript treats a large number of geometric algorithms, and
has stimulated much of the recent research.
For the most part, each of the geometric algorithms that we’ve discussed
is described in its own original reference. The convex hull algorithms treated
in Chapter 25 may be found in the papers by Jarvis, Graham, and Eddy. The
range searching methods of Chapter 26 come from Bentley and Freidman’s
survey article, which contains many references to original sources (of particular
interest is Bentley’s own original article on kD trees, written while he was an
undergraduate). The treatment of the closest point problems in Chapter 28 is
based on Shamos and Hoey’s 1976 paper, and the intersection algorithms of
Chapter 27 are from their 1975 paper and the article by Bentley and Ottmann.
But the best route for someone interested in learning more about geomet-
ric algorithms is to implement some, work with them and try to learn about
their behavior on different types of point sets. This field is still in its infancy
and the best algorithms are yet to be discovered.
J. L. Bentley, “Multidimensional binary search trees used for associative
searching,” Communications of the ACM, 18, 9 (September, 1975).
J. L. Bentley and J.H. Friedman, “Data structures for range searching,”
Computing Surveys, 11, 4 (December, 1979).
J. L. Bentley and T. Ottmann, “Algorithms for reporting and counting geomet-
ric intersections,” IEEE Transactions on Computing, C-28, 9 (September,
1979).
W. F. Eddy, “A new convex hull algorithm for planar sets,” ACM Transactions
on Mathematical Software, 3 (1977).
R. L. Graham, “An efficient algorithm for determining the convex hull of a
finite planar set,” Information Processing Letters, 1 (1972).
R. A. Jarvis, “On the identification of the convex hull of a finite set of points
in the plane,” Information Processing Letters, 2 (1973).
M. I. Shamos, Problems in Computational Geometry, unpublished manuscript,
1975.
M. I. Shamos and D. Hoey, “Closest-point problems,” in 16th Annual Sympo-
sium on Foundations of Computer Science, IEEE, 1975.
M. I. Shamos and D. Hoey, “Geometric intersection problems,” in 17th Annual
Symposium on Foundations of Computer Science, IEEE, 1976.