給定平面上N個點的座標,找出距離最近的兩個點(Java)
說實話這道題不太會,以下講解轉自一篇博客,代碼轉自另一篇(真是太菜了沒臉見人了…)
問題:平面點集求其中距離最近的兩個點及其距離。
思路:採用分治法,將“求n個點之間最小距離”問題劃分爲很多個“求n/t個點之間最小距離”問題。
(1)將lstPoint根據X座標由小到大排序得到點集pointsSortedX,方法很多,冒泡、選擇、插入、歸併,快排等,本文采用快排,其優點就不多說了。
(2)pointsSortedX爲一個點集,可以採用二分法分爲兩個數量均分的點集pointsX1([0,indexMid]),pointsX2([indexMid,Count-1]),對於每個分點集,求其中距離最近的兩個點及其距離,方法如前,採用遞歸求解;
(3)對於2個分點集,可得兩個最小距離,取其小者,爲分點集各自內的最小距離dis,但是仍然存在這種情況,即可能存在兩個點分別位於兩個分點集中,所以還需考慮2個分點集間的情況。而參考已求得的dis,2個分點集間區域可根據X座標取
X∈[pointsSortedX[indexMid].X - dis,pointsSortedX[indexMid].X + dis]範圍的點並構成臨時點集pointsTemp;
(4)將點集pointsTemp根據Y座標進行由小到大排序,對於每個點ptCurrent,求Y座標∈[ptCurrent.Y - dis, ptCurrent.Y + dis]的點ptCurrent的距離,並與dis取最小賦給dis;
圖解如下:
圖1 根據X座標排序
圖2 二分法分解
圖3 遞歸求解並考慮區域間點距離最小情況
————————————————
版權聲明:本文爲CSDN博主「哈市雪花」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/baidu_38621657/article/details/88367170
/*
* @Title divide
* @Description 求平面上距離最近的兩個點
* @author 滑技工廠
* @Date 2020/3/28
* @param [left, right, points]
* @return double
* @throws
*/
public static double divide(int left, int right, Point[] points) {
// 當前最小兩點距離,初始值設置爲無窮大
double curMinDis = 1e20;
// 如果只有一個點,則不存在最近兩點距離,返回無窮大
if (left == right) {
return curMinDis;
}
// 這裏是判斷是否爲只有兩個點,如果只有兩個點的話那麼直接求解。
if (left + 1 == right) {
return distance(points[left], points[right]);
}
// 分治法:第一步:分區,並求取左右分區最小兩點距離
// 通過右移運算除2,對區域進行合理的劃分,使得左右兩邊保持大致相等個數點
int middle = (left + right) >> 1;
double leftMinDis = divide(left, middle, points);
double rightMinDis = divide(middle, right, points);
curMinDis = (leftMinDis <= rightMinDis) ? leftMinDis : leftMinDis;
// 分治法:第二步:假設距離最近的兩點分別在左右分區中
// 關鍵代碼,距離最近的兩個點,一個位於左邊區域,一個位於右邊區域,x軸搜索範圍[middle-curMinDis, middle+curMinDis]
// 記錄搜索區間內的點的索引,便於進一步計算最小距離
List<Integer> validPointIndex = new ArrayList<>();
for (int i = left; i <= right; i++) {
if (Math.abs(points[middle].x - points[i].x) <= curMinDis) {
validPointIndex.add(i);
}
}
// 基於索引,進一步計算區間內最小兩點距離
for (int i = 0; i < validPointIndex.size() - 1; i++) {
for (int j = i + 1; j < validPointIndex.size(); j++) {
// 如果區間內的兩點y軸距離大於curMinDis,則沒必要計算了,因爲,它們的距離肯定大於curMinDis,
if (Math.abs(points[validPointIndex.get(i)].y
- points[validPointIndex.get(j)].y) > curMinDis) {
continue;
}
double tempDis = distance(points[validPointIndex.get(i)],
points[validPointIndex.get(j)]);
curMinDis = (tempDis < curMinDis) ? tempDis : curMinDis;
}
}
return curMinDis;
}
public static double distance(Point p1, Point p2) {
return Math.sqrt((p2.y - p1.y) * (p2.y - p1.y) + (p2.x - p1.x) * (p2.x - p1.x));
}