package divideconquer;
/**
* For a set of points in a coordinates system (10000 maximum),
* ClosestPair class calculates the two closest points.
* @author: anonymous
* @author: Marisa Afuera
*/
public final class ClosestPair {
/** Number of points */
int numberPoints = 0;
/** Input data, maximum 10000. */
private Location[] array;
/** Minimum point coordinate. */
Location point1 = null;
/** Minimum point coordinate. */
Location point2 = null;
/** Minimum point length. */
private static double minNum = Double.MAX_VALUE;
/** secondCount */
private static int secondCount = 0;
/**
* Constructor.
*/
ClosestPair(int points) {
numberPoints = points;
array = new Location[numberPoints];
}
/**
Location class is an auxiliary type to keep points coordinates.
*/
public static class Location {
double x = 0;
double y = 0;
/**
* @param xpar (IN Parameter) x coordinate
* @param ypar (IN Parameter) y coordinate
*/
Location(final double xpar, final double ypar) { //Save x, y coordinates
this.x = xpar;
this.y = ypar;
}
}
public Location[] createLocation(int numberValues) {
return new Location[numberValues];
}
public Location buildLocation(double x, double y){
return new Location(x,y);
}
/** xPartition function: arrange x-axis.
* @param a (IN Parameter) array of points
* @param first (IN Parameter) first point
* @param last (IN Parameter) last point
* @return pivot index
*/
public int xPartition(
final Location[] a, final int first, final int last) {
Location pivot = a[last]; // pivot
int pIndex = last;
int i = first - 1;
Location temp; // Temporarily store value for position transformation
for (int j = first; j <= last - 1; j++) {
if (a[j].x <= pivot.x) { // Less than or less than pivot
i++;
temp = a[i]; // array[i] <-> array[j]
a[i] = a[j];
a[j] = temp;
}
}
i++;
temp = a[i]; // array[pivot] <-> array[i]
a[i] = a[pIndex];
a[pIndex] = temp;
return i; // pivot index
}
/** yPartition function: arrange y-axis.
* @param a (IN Parameter) array of points
* @param first (IN Parameter) first point
* @param last (IN Parameter) last point
* @return pivot index
*/
public int yPartition(
final Location[] a, final int first, final int last) {
Location pivot = a[last]; // pivot
int pIndex = last;
int i = first - 1;
Location temp; // Temporarily store value for position transformation
for (int j = first; j <= last - 1; j++) {
if (a[j].y <= pivot.y) { // Less than or less than pivot
i++;
temp = a[i]; // array[i] <-> array[j]
a[i] = a[j];
a[j] = temp;
}
}
i++;
temp = a[i]; // array[pivot] <-> array[i]
a[i] = a[pIndex];
a[pIndex] = temp;
return i; // pivot index
}
/** xQuickSort function: //x-axis Quick Sorting.
* @param a (IN Parameter) array of points
* @param first (IN Parameter) first point
* @param last (IN Parameter) last point
*/
public void xQuickSort(
final Location[] a, final int first, final int last) {
if (first < last) {
int q = xPartition(a, first, last); // pivot
xQuickSort(a, first, q - 1); // Left
xQuickSort(a, q + 1, last); // Right
}
}
/** yQuickSort function: //y-axis Quick Sorting.
* @param a (IN Parameter) array of points
* @param first (IN Parameter) first point
* @param last (IN Parameter) last point
*/
public void yQuickSort(
final Location[] a, final int first, final int last) {
if (first < last) {
int q = yPartition(a, first, last); // pivot
yQuickSort(a, first, q - 1); // Left
yQuickSort(a, q + 1, last); // Right
}
}
/** closestPair function: find closest pair.
* @param a (IN Parameter) array stored before divide
* @param indexNum (IN Parameter) number coordinates divideArray
* @return minimum distance
*/
public double closestPair(final Location[] a, final int indexNum) {
Location[] divideArray = new Location[indexNum];
System.arraycopy(a, 0, divideArray, 0, indexNum); // Copy previous array
int totalNum = indexNum; // number of coordinates in the divideArray
int divideX = indexNum / 2; // Intermediate value for divide
Location[] leftArray = new Location[divideX]; //divide - left array
//divide-right array
Location[] rightArray = new Location[totalNum - divideX];
if (indexNum <= 3) { // If the number of coordinates is 3 or less
return bruteForce(divideArray);
}
//divide-left array
System.arraycopy(divideArray, 0, leftArray, 0, divideX);
//divide-right array
System.arraycopy(
divideArray, divideX, rightArray, 0, totalNum - divideX);
double minLeftArea = 0; //Minimum length of left array
double minRightArea = 0; //Minimum length of right array
double minValue = 0; //Minimum lengt
minLeftArea = closestPair(leftArray, divideX); // recursive closestPair
minRightArea = closestPair(rightArray, totalNum - divideX);
// window size (= minimum length)
minValue = Math.min(minLeftArea, minRightArea);
// Create window. Set the size for creating a window
// and creating a new array for the coordinates in the window
for (int i = 0; i < totalNum; i++) {
double xGap = Math.abs(divideArray[divideX].x - divideArray[i].x);
if (xGap < minValue) {
secondCount++; // size of the array
} else {
if (divideArray[i].x > divideArray[divideX].x) {
break;
}
}
}
// new array for coordinates in window
Location[] firstWindow = new Location[secondCount];
int k = 0;
for (int i = 0; i < totalNum; i++) {
double xGap = Math.abs(divideArray[divideX].x - divideArray[i].x);
if (xGap < minValue) { // if it's inside a window
firstWindow[k] = divideArray[i]; // put in an array
k++;
} else {
if (divideArray[i].x > divideArray[divideX].x) {
break;
}
}
}
yQuickSort(firstWindow, 0, secondCount - 1); // Sort by y coordinates
/* Coordinates in Window */
double length = 0;
// size comparison within window
for (int i = 0; i < secondCount - 1; i++) {
for (int j = (i + 1); j < secondCount; j++) {
double xGap = Math.abs(firstWindow[i].x - firstWindow[j].x);
double yGap = Math.abs(firstWindow[i].y - firstWindow[j].y);
if (yGap < minValue) {
length = Math.sqrt(Math.pow(xGap, 2) + Math.pow(yGap, 2));
// If measured distance is less than current min distance
if (length < minValue) {
// Change minimum distance to current distance
minValue = length;
// Conditional for registering final coordinate
if (length < minNum) {
minNum = length;
point1 = firstWindow[i];
point2 = firstWindow[j];
}
}
}
else {
break;
}
}
}
secondCount = 0;
return minValue;
}
/** bruteForce function: When the number of coordinates is less than 3.
* @param arrayParam (IN Parameter) array stored before divide
* @return
*/
public double bruteForce(final Location[] arrayParam) {
double minValue = Double.MAX_VALUE; // minimum distance
double length = 0;
double xGap = 0; // Difference between x coordinates
double yGap = 0; // Difference between y coordinates
double result = 0;
if (arrayParam.length == 2) {
// Difference between x coordinates
xGap = (arrayParam[0].x - arrayParam[1].x);
// Difference between y coordinates
yGap = (arrayParam[0].y - arrayParam[1].y);
// distance between coordinates
length = Math.sqrt(Math.pow(xGap, 2) + Math.pow(yGap, 2));
// Conditional statement for registering final coordinate
if (length < minNum) {
minNum = length;
}
point1 = arrayParam[0];
point2 = arrayParam[1];
result = length;
}
if (arrayParam.length == 3) {
for (int i = 0; i < arrayParam.length - 1; i++) {
for (int j = (i + 1); j < arrayParam.length; j++) {
// Difference between x coordinates
xGap = (arrayParam[i].x - arrayParam[j].x);
// Difference between y coordinates
yGap = (arrayParam[i].y - arrayParam[j].y);
// distance between coordinates
length =
Math.sqrt(Math.pow(xGap, 2) + Math.pow(yGap, 2));
// If measured distance is less than current min distance
if (length < minValue) {
// Change minimum distance to current distance
minValue = length;
if (length < minNum) {
// Registering final coordinate
minNum = length;
point1 = arrayParam[i];
point2 = arrayParam[j];
}
}
}
}
result = minValue;
}
return result; // If only one point returns 0.
}
/** main function: execute class.
* @param args (IN Parameter)
* @throws IOException If an input or output
* exception occurred
*/
public static void main(final String[] args) {
//Input data consists of one x-coordinate and one y-coordinate
ClosestPair cp = new ClosestPair(12);
cp.array[0]=cp.buildLocation(2,3);
cp.array[1]=cp.buildLocation(2,16);
cp.array[2]=cp.buildLocation(3,9);
cp.array[3]=cp.buildLocation(6,3);
cp.array[4]=cp.buildLocation(7,7);
cp.array[5]=cp.buildLocation(19,4);
cp.array[6]=cp.buildLocation(10,11);
cp.array[7]=cp.buildLocation(15,2);
cp.array[8]=cp.buildLocation(15,19);
cp.array[9]=cp.buildLocation(16,11);
cp.array[10]=cp.buildLocation(17,13);
cp.array[11]=cp.buildLocation(9,12);
System.out.println("Input data");
System.out.println("Number of points: "+ cp.array.length);
for (int i=0;i