How Does the Closest-Pair-of-Points Algorithm Work?
At a glance
- 1. Sort the points
Sort once by x-coordinate and once by y-coordinate, keeping each point’s identity so the two orders stay linked.
- 2. Split recursively
Divide the x-sorted points into halves and find the closest pair within each half.
- 3. Build the strip
Let delta be the better half-distance; keep points within delta of the dividing line, in y-order.
- 4. Check nearby points
For each strip point, compare it with at most the next seven points in y-order.
The closest-pair problem asks: given points in the plane, which two are nearest under ordinary Euclidean distance? (Assume ; if , no pair exists.) Checking every pair takes time. A divide-and-conquer algorithm solves it in time by limiting how many points must be checked near each recursive split.
The method below assumes two-dimensional points and Euclidean distance. It returns any one closest pair if there are ties. If the points are in a different dimension or use a different distance measure, the details and running time may change.
The key idea
Sort the points by -coordinate and divide the sorted list into two halves. Recursively find the closest pair in each half. Let be the smaller of those two distances.
A pair that is closer than cannot have both points in the same half; the recursive calls would already have found it. So a better pair, if one exists, must cross the dividing line. Both points must be within of that line, and their vertical separation must be less than . This leaves only a narrow vertical strip to inspect.
Sort the strip by -coordinate. For each point, it is enough to check the next seven points in that order, stopping sooner if the vertical gap exceeds . The geometric reason is that a rectangle of width and height can be divided into two -by- regions, one on each side of the split. Each region can be subdivided into four squares of side ; each small square has diameter less than , so it contains at most one point from that side. Thus at most eight points, including the point being considered, can occupy the relevant neighborhood.
Step-by-step algorithm
- Sort the points by -coordinate, and separately by -coordinate. Give each point an identity so you can tell which half it belongs to even if several points have the same coordinates.
- If a recursive subset has at most three points, check every pair directly.
- Split the -sorted list in half. Partition the -sorted list into the same two groups, preserving its order.
- Recursively find the closest pair in each half. Set to the smaller distance and keep that pair as the current best.
- Collect, in -order, the points whose horizontal distance from the dividing line is at most . For each point, check the next seven points in this strip, or fewer if their vertical gap is greater than . Update the best pair when you find a shorter distance.
A high-level version is:
ClosestPair(Px, Py):
if size(Px) <= 3:
return the closest pair found by checking every pair
split Px into Lx and Rx
split Py into Ly and Ry using point identities
(leftPair, leftDistance) = ClosestPair(Lx, Ly)
(rightPair, rightDistance) = ClosestPair(Rx, Ry)
bestPair = the better of leftPair and rightPair
delta = the smaller of leftDistance and rightDistance
S = points in Py within delta of the dividing line
for each point S[i], in y-order:
compare it with the next at most 7 points in S
stop when the y-gap exceeds delta
update bestPair and delta if a shorter pair is found
return bestPair
The strip is already in -order because it is filtered from . Preserving that order is essential: sorting the strip from scratch at every recursive call would add unnecessary work.
Worked example
Consider the points , , , and . The -sorted order is . Split it into and .
The distance in the left half is
The distance in the right half is
So the current best distance is . The dividing line is between the halves, at for this example. The strip contains the points in -order . In particular, the algorithm checks and across the split:
That is shorter than , so and are the closest pair. The strip check is what catches a pair that neither recursive call could find.
Why the running time is
The two recursive calls each handle about half the points. At each level, splitting the -ordered list and scanning the strip take total work; each strip point causes at most seven comparisons. Therefore the recurrence is
which gives . The initial sorting also takes , so it does not change the overall bound. Keep the points sorted by as the recursion proceeds rather than sorting anew at every level.
Common mistakes
- Checking only adjacent strip points: The closest cross-split pair need not be adjacent in -order. Check up to the next seven points, stopping when the -gap is too large.
- Sorting inside every recursive call: Re-sorting each subset by can lead to time. Sort once, then filter the existing -order at each split.
- Splitting only by coordinate when x-values tie: If points share the dividing -coordinate, a coordinate test alone may assign them inconsistently. Divide by their positions in the -sorted list and use point identities when partitioning the -sorted list.
- Ignoring duplicate points: If two input points coincide, the minimum distance is zero. Detect duplicates up front and return that pair; otherwise the positive-distance strip argument applies.
- Comparing square roots unnecessarily: To find the minimum, compare squared distances such as . Take a square root only if you need to report the distance itself.
References
- Computational Geometry: Algorithms and Applications, 3rd ed. — Mark de Berg, Otfried Cheong, Marc van Kreveld, and Mark Overmars
Spotted an error? Send a correction. Read how we write and check articles in our editorial policy.