算法分析:
方法一:穷举
1)算法描述:已知集合S中有n个点,一共可以组成n(n-1)/2对点对,蛮力法就是对这n(n-1)/2对点对逐对进行距离计算,通过循环求得点集中的最近点对
2)算法时间复杂度:算法一共要执行 n(n-1)/2次循环,因此算法复杂度为O(n2)
代码实现:
利用两个for循环可实现所有点的配对,每次配对算出距离然后更新最短距离.
方法二:分治
在二维空间里,可用分治法求解最近点对问题。预处理:分别根据点的x轴和y轴坐标进行排序,得到X和Y,很显然此时X和Y中的点就是S中的点。
代码如下:
import java.util.Arrays;
// 提供一个静态方法返回平面内最近点对:public static Point[] nearest(Point[] array)
// 其他的方法皆为私有的助手方法
public class NearestPoint {
// 返回给定点集中的最近点对,如果只有一个点,则返回只包含一个点的数组
public static Point[] nearest(Point[] array) {
Point[] cpArray = Arrays.copyOfRange(array, 0, array.length);
SortComparable.sort(cpArray);
return mergeNearest(cpArray, 0, cpArray.length - 1);
}
// 分治求最近点对
private static Point[] mergeNearest(Point[] points, int begin, int end) {
if (begin == end)
return new Point[] { points[begin] };
else {
int mid = (begin + end) / 2;
Point[] left = mergeNearest(points, begin, mid);
Point[] right = mergeNearest(points, mid + 1, end);
return merge(left, right, points, begin, mid, end);
}
}
// 合并左右两边,求最近点对
private static Point[] merge(Point[] left, Point[] right, Point[] points,
int begin, int mid, int end) {
if (left.length == 1 && right.length == 1)
return new Point[] { left[0], right[0] };
Point[] partNearest = partNearest(left, right);
return mergeNearest(points, partNearest, begin, mid, end);
}
// 比较左右两边,返回局部最近点对
private static Point[] partNearest(Point[] left, Point[] right) {
// 两个数组长度不可能同时为0
if (left.length == 1) {
return right;
} else if (right.length == 1) {
return left;
} else {
if (left[0].distance(left[1]) < right[0].distance(right[1]))
return left;
else
return right;
}
}
private static Point[] mergeNearest(Point[] points, Point[] partNearest,
int begin, int mid, int end) {
// 初始化两边在d范围内的点, 并按y坐标排序
Point[] left = null;
Point[] right = null;
Point[] nearest = partNearest;
double middle = (points[mid].getX() + points[mid + 1].getX()) / 2;
double d = partNearest[0].distance(partNearest[1]);
for (int i = mid; i >= begin - 1; i--) {
if (i != begin - 1) {
if (middle - points[i].getX() <= d)
continue;
} else {
left = Arrays.copyOfRange(points, i + 1, mid + 1);
SortComparable.sort(left, new PointYComparaotr());
break;
}
}
for (int i = mid + 1; i <= end + 1; i++) {
if (i != end + 1) {
if (points[i].getX() - middle <= d)
continue;
} else {
right = Arrays.copyOfRange(points, mid + 1, i);
SortComparable.sort(right, new PointYComparaotr());
break;
}
}
// 遍历left数组,在right中寻找符合条件的点
for (Point inLeft : left) {
for (int i = 0; i < right.length; i++) {
if (inLeft.getY() - right[i].getY() > d)
continue;
if (inLeft.getY() - right[i].getY() < -d)
break;
if (inLeft.distance(right[i]) < d) {
nearest = new Point[] { inLeft, right[i] };
d = inLeft.distance(right[i]);
}
}
}
return nearest;
}
}
测试代码:方法一和方法二输出一样的距离则输出true
public class TestNearestPoints {
static final int SIZE = 100;
public static void main(String[] args) {
PointGenerator pg = new PointGenerator(10000);
Point[] array = new Point[SIZE];
for(int i = 0; i < array.length; i++)
array[i] = pg.next();
Point[] nearP = NearestPoint.nearest(array);
double d = nearP[0].distance(nearP[1]);
System.out.println(nearest(array) == d);
}
private static double nearest(Point[] array) {
double d = 214748364; // the guard
for(int i = 0; i < array.length - 1; i++)
for(int j = i + 1; j < array.length; j++)
if(d > array[i].distance(array[j])) {
d = array[i].distance(array[j]);
}
return d;
}
}
测试代码中相关的PointGenerator类等,请参见:http://blog.csdn.net/qq_35328850/article/details/56279113