1. 程式人生 > >尋找最近點對演算法

尋找最近點對演算法

尋找最近點對演算法一般而言需要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; }