Algoteka
Log in to submit your own samples!

2D Closest Pair of Points Problem

Problem by oml1111
# Tech tags Title Creator Created date
1 0
2022-11-15 02:11
View all samples for this language (1 verified and 0 unverified)

O(n log n) Divide-and-conquer readable solution | C++ |

By oml1111 |
0 likes

A readable and commented \(O(n \log n)\) Divide-and-conquer solution to the closest pair of points problem (\(n\) is the number of points).

Code

#include<vector>
#include<cmath>
#include<algorithm>
#include<limits>


struct Vector2D {
    double x;
    double y;
    
    Vector2D operator-(Vector2D r) {
        return {x - r.x, y - r.y};
    }
    double operator*(Vector2D r) {
        return x * r.x + y * r.y;
    }
    
    double length() {
        return hypot(x, y);
    }
};


double closest_pair_divide_and_conquer(std::vector<Vector2D> points) {
    if(points.size() <= 1) {
        return std::numeric_limits<double>::infinity();
    } else if (points.size() == 2) {
        return (points[1] - points[0]).length();
    }
    
    std::sort(points.begin(), points.end(), [](Vector2D& left, Vector2D& right) {
        return left.x < right.x;
    });  // Sort points by x coordinates
    
    int mid_i = points.size() / 2;
    double min_dist = std::min(
        closest_pair_divide_and_conquer(std::vector<Vector2D>(points.begin(), points.begin()+mid_i)),
        closest_pair_divide_and_conquer(std::vector<Vector2D>(points.begin()+mid_i, points.end()))
    );  // Do the divide and conquer recursive call
    
    // Now we get the points that are in strips 
    double mid_x = (points[mid_i-1].x + points[mid_i].x) / 2.0f;
    std::vector<Vector2D> left_strip(mid_i);
    std::vector<Vector2D> right_strip(points.size()-mid_i);
    
    left_strip.resize(std::distance(
        left_strip.begin(),
        std::copy_if(points.begin(), points.begin()+mid_i, left_strip.begin(), [&](Vector2D point) {
            return mid_x - point.x < min_dist;
        })
    ));  // Populate left strip with points within min_dist
    right_strip.resize(std::distance(
        right_strip.begin(),
        std::copy_if(points.begin()+mid_i, points.end(), right_strip.begin(), [&](Vector2D point) {
            return point.x - mid_x < min_dist;
        })
    ));  // Populate right strip with points within min_dist
    
    // Now iterate over the strips and see if there is a closer pair across the mid_x line
    std::sort(left_strip.begin(), left_strip.end(), [](Vector2D& left, Vector2D& right) {
        return left.y < right.y;
    });  // Sort left strip by y coordinate
    std::sort(right_strip.begin(), right_strip.end(), [](Vector2D& left, Vector2D& right) {
        return left.y < right.y;
    });  // Sort right strip by y coordinate
    {
        // First point of right strip with y-coordinate within min_dist of the current point on left strip
        int begin = 0;
        // First point of right strip with y-coordinate more than min_dist above the current point on the left strip
        int end = 0;
        double strip_min_dist = min_dist;
        
        for(auto point : left_strip) {
            while(begin < (int)right_strip.size() && right_strip[begin].y <= point.y - min_dist) {
                begin++;
            }
            while(end < (int)right_strip.size() && right_strip[end].y < point.y + min_dist) {
                end++;
            }
            // Compare the point on the left strip to points on the right strip that can be within min_dist distance
            for(int i=begin; i<end; i++) {
                strip_min_dist = std::min(strip_min_dist, (right_strip[i] - point).length());
            }
        }
        min_dist = std::min(min_dist, strip_min_dist);
    }
    return min_dist;
}


int main() {
    std::vector<Vector2D> points = {
        {1, 2},
        {5, 6},
        {4, 8},
        {10, 4}
    };
    double result = closest_pair_divide_and_conquer(points);
    return 0;
}

Further reading

CMSC 451: Closest Pair of Points - cs.cmu.edu

References

functions
hypot en.cppreference.com cplusplus.com
std::copy_if en.cppreference.com cplusplus.com
std::distance en.cppreference.com cplusplus.com
std::min en.cppreference.com cplusplus.com
std::numeric_limits::infinity en.cppreference.com cplusplus.com
std::sort en.cppreference.com cplusplus.com
std::vector::begin en.cppreference.com cplusplus.com
std::vector::end en.cppreference.com cplusplus.com
std::vector::operator[] en.cppreference.com cplusplus.com
std::vector::resize en.cppreference.com cplusplus.com
std::vector::size en.cppreference.com cplusplus.com
std::vector::vector en.cppreference.com cplusplus.com
classes
std::numeric_limits en.cppreference.com cplusplus.com
std::vector en.cppreference.com cplusplus.com

Problem Description

Implement a solution for the 2D version of the closest pair of points problem. Create some instance of this problem and then compute the distance of the closest pair.

Closest pair of points problem - wikipedia.org

View sample discussion (0 comments)
View problem discussion (0 comments)