Cs · Computer Science

How Does the Closest-Pair-of-Points Algorithm Work?

Published By the 9to5Science editorial team

At a glance

  1. 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. 2. Split recursively

    Divide the x-sorted points into halves and find the closest pair within each half.

  3. 3. Build the strip

    Let delta be the better half-distance; keep points within delta of the dividing line, in y-order.

  4. 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 nn points in the plane, which two are nearest under ordinary Euclidean distance? (Assume n≥2n\ge2; if n<2n<2, no pair exists.) Checking every pair takes O(n2)O(n^2) time. A divide-and-conquer algorithm solves it in O(nlog⁡n)O(n \log n) 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 xx-coordinate and divide the sorted list into two halves. Recursively find the closest pair in each half. Let δ\delta be the smaller of those two distances.

A pair that is closer than δ\delta 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 δ\delta of that line, and their vertical separation must be less than δ\delta. This leaves only a narrow vertical strip to inspect.

Sort the strip by yy-coordinate. For each point, it is enough to check the next seven points in that order, stopping sooner if the vertical gap exceeds δ\delta. The geometric reason is that a rectangle of width 2δ2\delta and height δ\delta can be divided into two δ\delta-by-δ\delta regions, one on each side of the split. Each region can be subdivided into four squares of side δ/2\delta/2; each small square has diameter less than δ\delta, 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

  1. Sort the points by xx-coordinate, and separately by yy-coordinate. Give each point an identity so you can tell which half it belongs to even if several points have the same coordinates.
  2. If a recursive subset has at most three points, check every pair directly.
  3. Split the xx-sorted list in half. Partition the yy-sorted list into the same two groups, preserving its order.
  4. Recursively find the closest pair in each half. Set δ\delta to the smaller distance and keep that pair as the current best.
  5. Collect, in yy-order, the points whose horizontal distance from the dividing line is at most δ\delta. For each point, check the next seven points in this strip, or fewer if their vertical gap is greater than δ\delta. 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 yy-order because it is filtered from PyP_y. Preserving that order is essential: sorting the strip from scratch at every recursive call would add unnecessary work.

Worked example

Consider the points A=(0,0)A=(0,0), B=(2,5)B=(2,5), C=(4,2)C=(4,2), and D=(6,6)D=(6,6). The xx-sorted order is A,B,C,DA,B,C,D. Split it into A,BA,B and C,DC,D.

The distance in the left half is

d(A,B)=(2−0)2+(5−0)2=29≈5.39.\begin{aligned} d(A,B) &= \sqrt{(2-0)^2+(5-0)^2} \\ &= \sqrt{29} \approx 5.39. \end{aligned}

The distance in the right half is

d(C,D)=(6−4)2+(6−2)2=20≈4.47.\begin{aligned} d(C,D) &= \sqrt{(6-4)^2+(6-2)^2} \\ &= \sqrt{20} \approx 4.47. \end{aligned}

So the current best distance is δ=20\delta=\sqrt{20}. The dividing line is between the halves, at x=4x=4 for this example. The strip contains the points in yy-order A,C,B,DA,C,B,D. In particular, the algorithm checks CC and BB across the split:

d(B,C)=(4−2)2+(2−5)2=13≈3.61.d(B,C)=\sqrt{(4-2)^2+(2-5)^2}=\sqrt{13}\approx 3.61.

That is shorter than 20\sqrt{20}, so BB and CC are the closest pair. The strip check is what catches a pair that neither recursive call could find.

Why the running time is O(nlog⁡n)O(n \log n)

The two recursive calls each handle about half the points. At each level, splitting the yy-ordered list and scanning the strip take O(n)O(n) total work; each strip point causes at most seven comparisons. Therefore the recurrence is

T(n)=2T(n/2)+O(n),T(n)=2T(n/2)+O(n),

which gives T(n)=O(nlog⁡n)T(n)=O(n\log n). The initial sorting also takes O(nlog⁡n)O(n\log n), so it does not change the overall bound. Keep the points sorted by yy 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 yy-order. Check up to the next seven points, stopping when the yy-gap is too large.
  • Sorting inside every recursive call: Re-sorting each subset by yy can lead to O(nlog⁡2n)O(n\log^2 n) time. Sort once, then filter the existing yy-order at each split.
  • Splitting only by coordinate when x-values tie: If points share the dividing xx-coordinate, a coordinate test alone may assign them inconsistently. Divide by their positions in the xx-sorted list and use point identities when partitioning the yy-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 (x1−x2)2+(y1−y2)2(x_1-x_2)^2+(y_1-y_2)^2. Take a square root only if you need to report the distance itself.

References

  1. 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.