分治法尋找最鄰近的點對

來源:互聯網
上載者:User
問題描述:

在二維平面內給定n個點,尋找這些點中舉例最近的兩個點;

思路:

我們發現如果要將全部的點兩兩比較,則最起碼需要O(n^2),因此我們的思路是如果要求與某個點A距離最近的點,則需要縮小範圍,不用每個點都比較;


我們需要使用分治法來求解;

首先我們需要定義一些變數:

Px:對於點按照x座標排序;

Py:對於點按照y座標排序;

Qx:對於左部分的點按照x座標排序;

Qy:對於部分的點按照y座標排序;

Rx:對於右部分的點按照x座標排序;

Ry:對於右部分的點按照y座標排序;

遞迴的出口就是如果只有三個點以內,則直接兩兩計算距離,並返回最小距離;


我們可以從上面清晰的看出:每次將問題分割成兩個小問題,因此T(n) = 2*T(n/2)+f(n);

f(n)是問題分隔和組合的消耗;

分隔時需要計算Qx,Qy,Rx,Ry,因此花費O(n)

組合時已經計算出了Q和R地區的最小距離,d = min(d1,d2)我們需要計算一個點在Q,一個點在R的最小距離,我們需要做如下步驟:

(1)對於分隔Q和R的線,向左和向右拓寬d,落在這個地區中的點都有可能是最小距離的點對,記為S; O(n)

(2)我們對S按照y排序後為Sy,對於Sy中每個點只需要計算與他的x、y座標相差 2*d之內的點(最多15個點); O(n)

(3)計算出S地區的最小距離後與d比較,取較小者;
O(1)


因此f(n) = O(n)

T(n) = 2*T(n/2) + O(n)  ===>   T(n) = O(nlogn)

代碼:

import java.util.ArrayList;import java.util.Arrays;import java.util.Comparator;public class Test {public static void main(String[] args) {initializePoint();Point[]result = closest_pair(P);dist = distance(result);System.out.println("距離最近的兩點為:");print(result);System.out.println("距離為:"+dist);}private static double dist;private static Point[] P;private static Comparator<Point> ycompar = new Comparator<Point>() {  //根據y座標比較的比較子@Overridepublic int compare(Point o1, Point o2) {if(o1.y<o2.y){return -1;}else if(o1.y>o2.y){return 1;}return 0;}};private static Comparator<Point> xcompar = new Comparator<Point>() {  //根據x座標比較的比較子@Overridepublic int compare(Point o1, Point o2) {if(o1.x<o2.x){return -1;}else if(o1.x>o2.x){return 1;}return 0;}};//初始化點數組/** * (0,0) * (5,8) * (9,5) * (10,20) * (100,100) */private static void initializePoint() {P = new Point[5];for(int i=0;i<P.length;i++){P[i] = new Point();}P[0].x = 10;P[0].y = 20;P[1].x = 0;P[1].y = 0;P[2].x = 100;P[2].y = 100;P[3].x = 5;P[3].y = 8;P[4].x = 9;P[4].y = 5;}//主函數public static Point[] closest_pair(Point[] points) {Point[] px = points.clone();Arrays.sort(px,xcompar);Point[] py = points.clone();Arrays.sort(py,ycompar);Point[] result = closest_pair_rec(px,py);return result;}public static Point[] closest_pair_rec(Point[]px,Point[]py){Point minFirstPoint = null;Point minSecondPoint = null;double mindistance = 0;if(px.length<=3){//出口double mindist = Double.MAX_VALUE;int mini = 0;int minj = 0;for(int i=0;i<px.length;i++){for(int j=i+1;j<px.length;j++){if(mindist>distance(new Point[]{px[i],px[j]})){mindist = distance(new Point[]{px[i],px[j]});mini = i;minj = j;}}}return new Point[]{px[mini],px[minj]};}Point[] Q = Arrays.copyOfRange(px, 0, px.length/2+1);Point[] R = Arrays.copyOfRange(px, px.length/2+1, px.length);Point[] Qx = Q.clone();Arrays.sort(Qx, xcompar);Point[] Qy = Q.clone();Arrays.sort(Qy, ycompar);Point[] Rx = R.clone();Arrays.sort(Rx, xcompar);Point[]Ry = R.clone();Arrays.sort(Ry, ycompar);Point[] q = closest_pair_rec(Qx,Qy);Point[] r = closest_pair_rec(Rx,Ry);double qd = distance(q);double rd = distance(r);double delta = Math.min(qd,rd);if(delta==qd){minFirstPoint = q[0];minSecondPoint = q[1];}else{minFirstPoint = r[0];minSecondPoint = r[1];}mindistance = delta;int maxx = Qx[Qx.length-1].x;//分割線//找到與分割線距離小於delta的部分點放到S中ArrayList<Point> Stmp = new ArrayList<Point>();for(int i=0;i<px.length;i++){if(Math.abs(px[i].x-maxx)<delta){Stmp.add(px[i]);}}Point[]S = Stmp.toArray(new Point[0]);Point[] Sy = S.clone();Arrays.sort(Sy,ycompar);//尋找15個點之內的點,並比較距離,找出最小距離的得點 ,每個點至多比較8個點,因此複雜度為O(8n)double secondMinDistance = Double.MAX_VALUE;Point tmpminFirst = null;Point tmpminSecond = null;for(int i=0;i<Sy.length;i++){Point basep = Sy[i];for(int j=i+1;j<Sy.length;j++){Point compp = Sy[j];if((compp.y-basep.y < 2*delta)&&Math.abs(compp.x-basep.x)<2*delta){//如果在15個點之內,即x和y座標相差都在2*delta之內double tmpdis = distance(new Point[]{basep,compp});if(secondMinDistance>tmpdis){secondMinDistance = tmpdis;tmpminSecond = compp;tmpminFirst = basep;}}else{break;}}}if(secondMinDistance<mindistance){return new Point[]{tmpminFirst,tmpminSecond};}else{return new Point[]{minFirstPoint,minSecondPoint};}}private static double distance(Point[] q) {return Math.pow(Math.pow(q[0].x-q[1].x,2)+Math.pow(q[0].y-q[1].y,2), 0.5);}private static void print(Point[]ps){for(Point p:ps){System.out.println("x="+p.x+",y="+p.y);}}}class Point{int x;int y;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.