From f111af62b61ad008e43253dca3f8a62dac8d4e7d Mon Sep 17 00:00:00 2001 From: Dithi Date: Thu, 17 Apr 2025 19:23:33 +0530 Subject: [PATCH] Added RandomizedClosestPair code and test --- .../randomized/RandomizedClosestPair.java | 108 ++++++++++++++++++ .../randomized/RandomizedClosestPairTest.java | 45 ++++++++ 2 files changed, 153 insertions(+) create mode 100644 src/main/java/com/thealgorithms/randomized/RandomizedClosestPair.java create mode 100644 src/test/java/com/thealgorithms/randomized/RandomizedClosestPairTest.java diff --git a/src/main/java/com/thealgorithms/randomized/RandomizedClosestPair.java b/src/main/java/com/thealgorithms/randomized/RandomizedClosestPair.java new file mode 100644 index 000000000000..92b28be75223 --- /dev/null +++ b/src/main/java/com/thealgorithms/randomized/RandomizedClosestPair.java @@ -0,0 +1,108 @@ +package com.thealgorithms.randomized; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.ArrayList; +import java.util.Random; + +/** + * Randomized Closest Pair of Points Algorithm + * + * Use Case: + * - Efficiently finds the closest pair of points in a 2D plane. + * - Applicable in computational geometry, clustering, and graphics. + * + * Time Complexity: + * - Expected: O(n log n) using randomized divide and conquer + * + * @see Closest Pair of Points - Wikipedia + */ +public final class RandomizedClosestPair { + + // Prevent instantiation of utility class + private RandomizedClosestPair() { + throw new UnsupportedOperationException("Utility class"); + } + + public static class Point { + public final double x, y; + public Point(double x, double y) { + this.x = x; + this.y = y; + } + } + + public static double findClosestPairDistance(Point[] points) { + List shuffled = new ArrayList<>(Arrays.asList(points)); + Collections.shuffle(shuffled, new Random()); + + Point[] px = shuffled.toArray(new Point[0]); + Arrays.sort(px, Comparator.comparingDouble(p -> p.x)); + + Point[] py = px.clone(); + Arrays.sort(py, Comparator.comparingDouble(p -> p.y)); + + return closestPair(px, py); + } + + private static double closestPair(Point[] px, Point[] py) { + int n = px.length; + if (n <= 3) { + return bruteForce(px); + } + + int mid = n / 2; + Point midPoint = px[mid]; + + Point[] Qx = Arrays.copyOfRange(px, 0, mid); + Point[] Rx = Arrays.copyOfRange(px, mid, n); + + List Qy = new ArrayList<>(); + List Ry = new ArrayList<>(); + for (Point p : py) { + if (p.x <= midPoint.x) Qy.add(p); + else Ry.add(p); + } + + double d1 = closestPair(Qx, Qy.toArray(new Point[0])); + double d2 = closestPair(Rx, Ry.toArray(new Point[0])); + + double d = Math.min(d1, d2); + + List strip = new ArrayList<>(); + for (Point p : py) { + if (Math.abs(p.x - midPoint.x) < d) { + strip.add(p); + } + } + + return Math.min(d, stripClosest(strip, d)); + } + + private static double bruteForce(Point[] points) { + double min = Double.POSITIVE_INFINITY; + for (int i = 0; i < points.length; i++) { + for (int j = i + 1; j < points.length; j++) { + min = Math.min(min, distance(points[i], points[j])); + } + } + return min; + } + + private static double stripClosest(List strip, double d) { + double min = d; + int n = strip.size(); + for (int i = 0; i < n; i++) { + for (int j = i + 1; j < n && (strip.get(j).y - strip.get(i).y) < min; j++) { + min = Math.min(min, distance(strip.get(i), strip.get(j))); + } + } + return min; + } + + private static double distance(Point p1, Point p2) { + return Math.hypot(p1.x - p2.x, p1.y - p2.y); + } +} diff --git a/src/test/java/com/thealgorithms/randomized/RandomizedClosestPairTest.java b/src/test/java/com/thealgorithms/randomized/RandomizedClosestPairTest.java new file mode 100644 index 000000000000..5b402f3be90d --- /dev/null +++ b/src/test/java/com/thealgorithms/randomized/RandomizedClosestPairTest.java @@ -0,0 +1,45 @@ +package com.thealgorithms.randomized; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.thealgorithms.randomized.RandomizedClosestPair.Point; +import org.junit.jupiter.api.Test; + +public class RandomizedClosestPairTest { + + @Test + public void testClosestPairBasic() { + Point[] points = new Point[] { + new Point(2, 3), + new Point(12, 30), + new Point(40, 50), + new Point(5, 1), + new Point(12, 10), + new Point(3, 4) + }; + double result = RandomizedClosestPair.findClosestPairDistance(points); + assertEquals(Math.hypot(1, 1), result, 0.01); // Closest pair: (2,3) and (3,4) + } + + @Test + public void testIdenticalPoints() { + Point[] points = new Point[] { + new Point(0, 0), + new Point(0, 0), + new Point(1, 1), + }; + double result = RandomizedClosestPair.findClosestPairDistance(points); + assertEquals(0.0, result, 0.00001); + } + + @Test + public void testMinimalCase() { + Point[] points = new Point[] { + new Point(0, 0), + new Point(3, 4) + }; + double result = RandomizedClosestPair.findClosestPairDistance(points); + assertEquals(5.0, result, 0.00001); + } +} +