尋找最近點對演算法
阿新 • • 發佈:2019-01-08
尋找最近點對演算法一般而言需要O(n^2)的時間複雜度,即列舉法,分別計算每兩個點對之間的距離,取最小。
但是還有一種分治演算法理論上可以將時間複雜度減小到O(n.log n)的級別。但是由於遞迴的開銷,可能效果並不一定好,具體還要看問題特點。
演算法描述: ①若問題規模小於3,直接列舉法求解。 ②否則,將點集按照x座標排序,取中間點。 ③以中間點的xm座標為邊界,左右分別遞迴求解,得到左右最短距離 ④取左右兩邊遞迴結果的最小值a,取出x座標在xm-a到xm+a之間的點集 ⑤對於中間區域的點集,按照y座標排序
⑥對於每一個點,依次計算y座標比它大的7個點,計算最小距離。
⑦將中間區域的最小距離與a比較,取最小值返回。
下面是java程式碼:
/** * @param pointList * @return 最短距離 * @description 使用分治演算法尋找最短點對的距離 */ private static double findNearestPair(List<Point> pointList, int start, int end) {
if (end - start <= 3) { //當點的個數小於三個的時候,直接求解
return simpleNearestPair(pointList);
}
Collections.sort(pointList, new PointXComparator()); //按照x排序
int mid = (end + start) / 2;
Point midPoint = pointList.get(mid);
double res1 = findNearestPair(pointList, start, mid);
double res2 = findNearestPair(pointList, mid, end);
double res3 = Math.min(res1, res2);
double res = -1;
//構造中間條狀區域的點集合
ArrayList<Point> pointByY = new ArrayList<>();
for (int i = start; i < end; i++) {
if (Math.abs(pointList.get(i).x - midPoint.x) <= res3) {
pointByY.add(pointList.get(i));
}
}
//對於每個點狀區域的點,計算可能的跨越左右兩邊的最小值
Collections.sort(pointList, new PointYComparator()); //按照x排序
for (int k = 0; k < pointByY.size(); k++) {
int num = 0;
for (int i = k + 1; i < pointByY.size(); i++) {
if (num >= 7) {
break;
}
double tmp = pointByY.get(k).calDis(pointByY.get(i));
if (tmp < res || Math.abs(res + 1) < 0.000001) {
res = tmp;
}
}
}
return (Math.abs(res + 1) > 0.000001 && res < res3) ? res : res3;
}
/** * @param pointList * @return * @description 樸素尋找最短距離方法 */ private static double simpleNearestPair(List<Point> pointList) { double res = -1; for (Point p1 : pointList) { for (Point p2 : pointList) { if (p1 == p2) { continue; } double dis = p1.calDis(p2); if (Math.abs(res + 1) < 0.000001 || res > dis) { res = dis; } } } return res; }
演算法描述: ①若問題規模小於3,直接列舉法求解。 ②否則,將點集按照x座標排序,取中間點。 ③以中間點的xm座標為邊界,左右分別遞迴求解,得到左右最短距離 ④取左右兩邊遞迴結果的最小值a,取出x座標在xm-a到xm+a之間的點集 ⑤對於中間區域的點集,按照y座標排序
下面是java程式碼:
/** * @param pointList * @return 最短距離 * @description 使用分治演算法尋找最短點對的距離 */ private static double findNearestPair(List<Point> pointList, int start, int end) {
/** * @param pointList * @return * @description 樸素尋找最短距離方法 */ private static double simpleNearestPair(List<Point> pointList) { double res = -1; for (Point p1 : pointList) { for (Point p2 : pointList) { if (p1 == p2) { continue; } double dis = p1.calDis(p2); if (Math.abs(res + 1) < 0.000001 || res > dis) { res = dis; } } } return res; }