|
| 1 | +package ch_22.exercise22_07; |
| 2 | + |
| 3 | +import java.util.ArrayList; |
| 4 | +import java.util.Arrays; |
| 5 | +import java.util.List; |
| 6 | +import java.util.Random; |
| 7 | + |
| 8 | +/** |
| 9 | + * *22.7 (Closest pair of points) Section 22.8 introduced an algorithm for finding the |
| 10 | + * closest pair of points using a divide-and-conquer approach. |
| 11 | + * <p> |
| 12 | + * Implement the algorithm to meet the following requirements: |
| 13 | + * ■ Define the classes Point and CompareY in the same way as in Programming Exercise 20.4. |
| 14 | + * ■ Define a class named Pair with the data fields p1 and p2 to represent two |
| 15 | + * points, and a method named getDistance() that returns the distance |
| 16 | + * between the two points. |
| 17 | + * </p> |
| 18 | + * ---------------------------------------------------------------------- <br> |
| 19 | + * ■ Implement the following methods: |
| 20 | + * /** Return the distance of the closest pair of points * |
| 21 | + * public static Pair getClosestPair(double[][] points) |
| 22 | + * ---------------------------------------------------------------------- <br> |
| 23 | + * /** Return the distance of the closest pair of points |
| 24 | + * public static Pair getClosestPair(Point[] points) |
| 25 | + * ---------------------------------------------------------------------- <br> |
| 26 | + * /** Return the distance of the closest pair of points |
| 27 | + * in pointsOrderedOnX[low..high]. This is a recursive |
| 28 | + * method. pointsOrderedOnX and pointsOrderedOnY are |
| 29 | + * not changed in the subsequent recursive calls. * |
| 30 | + * public static Pair distance(Point[] pointsOrderedOnX, int low, int high, Point[] pointsOrderedOnY) |
| 31 | + * ************************************************************************************************* |
| 32 | + * <p> |
| 33 | + * From Section 22.8: |
| 34 | + * LISTING 22.8 Algorithm for Finding the Closest Pair |
| 35 | + * Step 1: Sort the points in increasing order of x-coordinates. For the |
| 36 | + * points with the same x-coordinates, sort on y-coordinates. This results |
| 37 | + * in a sorted list S of points. |
| 38 | + * Step 2: Divide S into two subsets, S1 and S2, of equal size using the |
| 39 | + * midpoint in the sorted list. Let the midpoint be in S1. Recursively find |
| 40 | + * the closest pair in S1 and S2. Let d1 and d2 denote the distance of the |
| 41 | + * closest pairs in the two subsets, respectively. |
| 42 | + * Step 3: Find the closest pair between a point in S1 and a point in S2 and |
| 43 | + * denote their distance as d3 |
| 44 | + * </p> |
| 45 | + */ |
| 46 | +public class Exercise22_07 { |
| 47 | + private static Point[] S = new Point[]{new Point(65.72438591548975, 167.6922117473909), |
| 48 | + new Point(182.85174298311438, 575.9888358534622), |
| 49 | + new Point(240.22902231427315, 175.37793004083213), |
| 50 | + new Point(317.5674265676426, 278.78240371327325), |
| 51 | + new Point(356.00061370323124, 337.3921411106672), |
| 52 | + new Point(302.54686547351093, 59.079345054498475), |
| 53 | + new Point(163.48579149126033, 749.1901740238649), |
| 54 | + new Point(277.76518877799515, 420.1256294206885), |
| 55 | + new Point(108.51033510595356, 21.982331832110937), |
| 56 | + new Point(108.5270214151543, 160.55324389043895), |
| 57 | + }; |
| 58 | + |
| 59 | + public static void main(String[] args) { |
| 60 | + Pair closestPair = getClosestPair(S); |
| 61 | + System.out.println("Closest Pair is: "); |
| 62 | + System.out.println(closestPair.toString()); |
| 63 | + |
| 64 | + } |
| 65 | + |
| 66 | + /** |
| 67 | + * Return the distance of the closest pair of points |
| 68 | + */ |
| 69 | + public static Pair getClosestPair(double[][] points) { |
| 70 | + /* Convert to Point[] */ |
| 71 | + Point[] pts = new Point[points.length]; |
| 72 | + int idx = 0; |
| 73 | + for (double[] pt : points) { |
| 74 | + pts[idx] = new Point(pt[0], pt[1]); |
| 75 | + idx++; |
| 76 | + } |
| 77 | + /* Use Point[] method to share common logic */ |
| 78 | + return getClosestPair(pts); |
| 79 | + } |
| 80 | + |
| 81 | + /** |
| 82 | + * Return the distance of the closest pair of points |
| 83 | + */ |
| 84 | + public static Pair getClosestPair(Point[] pointsOrderedOnX) { |
| 85 | + /* Sort Points by X first order, see Point.java */ |
| 86 | + Arrays.sort(pointsOrderedOnX); |
| 87 | + /* Create deep copy of pointsOrderedOnX array */ |
| 88 | + Point[] pointsOrderedOnY = pointsOrderedOnX.clone(); |
| 89 | + /* Sort pointsOrderedOnY by Y first order, see CompareY.java*/ |
| 90 | + Arrays.sort(pointsOrderedOnY, new CompareY()); |
| 91 | + /* Start recursion at low = startIndex, and high = endIndex */ |
| 92 | + return distance(pointsOrderedOnX, 0, pointsOrderedOnX.length - 1, pointsOrderedOnY); |
| 93 | + |
| 94 | + } |
| 95 | + |
| 96 | + /** |
| 97 | + * Return the distance of the closest pair of points |
| 98 | + * in pointsOrderedOnX[low..high]. This is a recursive |
| 99 | + * method. pointsOrderedOnX and pointsOrderedOnY are |
| 100 | + * not changed in the subsequent recursive calls. |
| 101 | + */ |
| 102 | + public static Pair distance(Point[] pointsOrderedOnX, |
| 103 | + int low, int high, Point[] pointsOrderedOnY) { |
| 104 | + if (low >= high) {/* Recursive stopping condition */ |
| 105 | + return null; |
| 106 | + } else if (low + 1 == high) { /* Only 2 Points possible to pair: pointsOrderedOnX[low], pointsOrderedOnX[high] */ |
| 107 | + return new Pair(pointsOrderedOnX[low], pointsOrderedOnX[high]); |
| 108 | + } else { |
| 109 | + /* Divide and Conquer */ |
| 110 | + int mid = (low + high) / 2; |
| 111 | + /* Split sorted in half into S1 and S2, let d1 and d2 denote the distance of the closest pair in each subset */ |
| 112 | + Pair S1 = distance(pointsOrderedOnX, low, mid, pointsOrderedOnY); //d1 |
| 113 | + Pair S2 = distance(pointsOrderedOnX, mid + 1, high, pointsOrderedOnY); // d2 |
| 114 | + /* Find minDistance = min(d1,d2) distance */ |
| 115 | + double d = 0; |
| 116 | + Pair p = null; |
| 117 | + if (S1 != null && S2 != null) { |
| 118 | + double leftPairDistance = S1.getDistance(); |
| 119 | + double rightPairDistance = S1.getDistance(); |
| 120 | + d = Math.min(leftPairDistance, rightPairDistance); |
| 121 | + p = leftPairDistance == d ? S1 : S2; |
| 122 | + } else if (S1 != null) { |
| 123 | + d = S1.getDistance(); |
| 124 | + p = S1; |
| 125 | + } else if (S2 != null) { |
| 126 | + d = S2.getDistance(); |
| 127 | + p = S2; |
| 128 | + } |
| 129 | + |
| 130 | + List<Point> stripL = new ArrayList<>(); |
| 131 | + List<Point> stripR = new ArrayList<>(); |
| 132 | + /* Obtain stripL and stripR */ |
| 133 | + for (Point point : pointsOrderedOnY) { |
| 134 | + /* if (p is in S1 and mid.x – p.x <= d) */ |
| 135 | + if (point.getX() <= pointsOrderedOnX[mid].getX() && pointsOrderedOnX[mid].getX() - point.getX() <= d) { |
| 136 | + stripL.add(point); |
| 137 | + /* else if (p is in S2 and p.x - mid.x <= d) */ |
| 138 | + } else if (point.getX() > pointsOrderedOnX[mid].getX() && point.getX() - pointsOrderedOnX[mid].getX() <= d) { |
| 139 | + stripR.add(point); |
| 140 | + } |
| 141 | + } |
| 142 | + |
| 143 | + int r = 0; // The index of the point in stripE |
| 144 | + for (Point point : stripL) { |
| 145 | + // Skip the points in stripR below p.y - d |
| 146 | + while (r < stripR.size() && stripR.get(r).getY() <= point.getY() - d) { |
| 147 | + r++; |
| 148 | + } |
| 149 | + int r1 = r; |
| 150 | + while (r1 < stripR.size() && Math.abs(stripR.get(r1).getY() - point.getY()) <= d) { |
| 151 | + /* Check if (p, q[r1]) is a possible closest pair */ |
| 152 | + if (new Pair(point, stripR.get(r1)).getDistance() < d) { |
| 153 | + d = new Pair(point, stripR.get(r1)).getDistance(); |
| 154 | + p.setP1(point); |
| 155 | + p.setP2(stripR.get(r1)); |
| 156 | + } |
| 157 | + r1++; |
| 158 | + } |
| 159 | + } |
| 160 | + return p; |
| 161 | + } |
| 162 | + } |
| 163 | +} |
0 commit comments