程式設計之美2 11 尋找最近的點對

2021-09-06 13:24:10 字數 4703 閱讀 9543

求點集中的最近點對有以下兩種方法:

設p1=(x1, y1), p2=(x2, y2), …, pn=(xn, yn)是平面上n個點構成的集合s,設計演算法找出集合s中距離最近的點對。

解體思路

1、蠻力法(適用於點的數目比較小的情況下)

1)演算法描述:已知集合s中有n個點,一共可以組成n(n-1)/2對點對,蠻力法就是對這n(n-1)/2對點對逐對進行距離計算,通過迴圈求得點集中的最近點對:

2)**描述:

double mindistance = double.maxvalue;  //設定乙個mindistance儲存最近點對的距離,初始值為無窮大

int pointindex1,pointindex2; //設定pointindex1,pointindex2分別儲存最近點對的兩個點編號

for (i=1; i< n; i++)    //迴圈計算n(n-1)/2對點對的距離

3)演算法時間複雜度:演算法一共要執行 n(n-1)/2次迴圈,因此演算法複雜度為o(n2)

2、分治法

1)演算法描述:已知集合s中有n個點,分治法的思想就是將s進行拆分,分為2部分求最近點對。演算法每次選擇一條垂線l,將s拆分左右兩部分為sl和sr

,l一般取點集s中所有點的中間點的x座標來劃分,這樣可以保證sl和sr中的點數目各為n/2,

(否則以其他方式劃分s,有可能導致sl和sr

中點數目乙個為1,乙個為n-1,不利於演算法效率,要盡量保持樹的平衡性)

依次找出這兩部分中的最小點對距離:δ

l和δr,記sl和sr

中最小點對距離δ= min(δ

l,δr),如圖1:

以l為中心,δ為半徑劃分乙個長帶,最小點對還有可能存在於sl和sr的交界處,如下圖2左圖中的虛線帶,p點和q點分別位於sl和sr

的虛線範圍內,在這個範圍內,p點和q點之間的距離才會小於δ,最小點對計算才有意義。

對於sl虛框範圍內的p點,在sr

虛框中與p點距離小於δ的頂多只有六個點,就是圖二右圖中的2個正方形的6的頂點。這個可以反推證明,如果右邊這2個正方形內有7個點與p點距離小於δ,例如q點,則q點與下面正方形的四個頂點距離小於δ,則和δ為sl

和sr中的最小點對距離相矛盾。因此對於sl虛框中的p點,不需求出p點和右邊虛線框內所有點距離,只需計算sr中與p點y座標距離最近的6個點,就可以求出最近點對,節省了比較次數。

(否則的話,最壞情形下,在sr虛框中有可能會有n/2個點,對於sl虛框中的p點,每次要比較n/2次,浪費了演算法的效率)

**描述

1)對點集s的點x座標進行公升序排序,獲得點集point array

2)令δ=∞;   //δ為最大點位距離

3)divide_conquer(point array,left,right)  //分治法

if (left == right) then δ=∞;   //如果point中只有乙個點,則δ=∞

return δ;

else if (right - left ==1) // point中只有2個點,則直接求這兩個點的距離

δ=d(sx.[0],)sx.[1]); 

return δ;

else    //如果point中多於2個點,則將point分治,以中心點畫線,將point分為左右兩部分a和

b,mid = (leftindex + rightindex)>>1;   //mid為當前段中的中間點index           

double d1 = closest_pair(leftindex,mid);                  

double d2 = closest_pair(mid +1,rightindex); 

d  =min(d1,d2);  

listleftlist = new ();

listlrightlist = new ();

// 分離出寬度為d,距point[mid]<=d的區間,其實也就是化了兩條平行於x= point[mid].x的豎線。(之後還需要根據左邊a的p,在右邊選距離p.y<=d,在化兩條橫線,這樣乙個動態的矩形也就化出來了。(矩形包含兩個正方形,一條邊重合,也就是最多存在6(頂)點(鴿巢原理),可能滿足條件     (如上面的圖figure2)

迴圈遍歷 陣列

1. if (fabs(point[mid].x -point[i].x) <=d && i <= mid)

leftlist.add(point[i] //左邊符合條件的點

2. if (fabs(point[mid].x -point[i].x) <=d && i > mid)

rightlist.add(point[i]) //右邊符合條件的點

// 線性掃瞄

foreach ( point leftpoint in leftlist)

}  

return d;       

詳細的**如下:

using system;

using system.collections.generic;

using system.linq;

using system.text;

using system.threading.tasks;

double x;

public double x

set

}double y;

public double y

set

}public static void copy (point a, point b)

bool compyx(point a, point b)

return a.y < b.y;

}public static double dis(point a, point b)

}public static class sorthelper

}

public static void mergebyx(point array, int increasement)

int lastindex = array.length - 1;

int l1 = 0; //第1個有序表的起始位置

int h1 = 0; //第1個有序表的結束位置

int l2 = 0; //第2個有序表的起始位置

int h2 = 0; //第2個有序表的結束位置

int m = 0; //臨時表的初始位置

// 注意這裡的臨界條件(l2要存在,l2的index是: l1 + increasement<=lastindex)

while (l1 + increasement <= lastindex)

else //第2個有序表記錄的關鍵碼小於第1個有序表記錄的關鍵碼

}//第1個有序表中還有記錄沒有排序完

while (i <= h1)

//第2個有序表中還有記錄沒有排序完

while (j <= h2)

l1 = h2 + 1;

}//原順序表中還有記錄沒有排序完

while (l1 <= lastindex)

//臨時順序表中的記錄複製到原順序表,使原順序表中的記錄有序

for (int i = 0; i < array.length; i++)

}

}public class calculatehelper

public double getclosetdistant(point array, int leftindex, int rightindex)

// 情況二:當前區域只有兩個點時,直接返回這兩個點的距離 (出口二)

if (leftindex + 1 == rightindex)

// 按照x排序

sorthelper.mergesortbyx(array);

// 情況三,當前區域點的個數大於2的時候,需要採用分治法,把當前區域分成左右兩個部分,直到滿足情況一或二

int midindex = (leftindex + rightindex) >> 1;

double leftdistance = getclosetdistant(array, leftindex, midindex);

double rightdistance = getclosetdistant(array, midindex + 1, rightindex);

distant = math.min(leftdistance, rightdistance); //求出左右兩邊區域的最小距離

if (distant < 0.43)

for (int i = leftindex; i <= midindex; i++) //遍歷左邊的點

if (distant < 0.43)}}

}}if (distant < 0.43)

return distant;}}

}// 主函式

static void main(string args)

《程式設計之美》 尋找最近點對

問題 給定平面上兩個點的座標,找出距離最近的兩個點。分析與解法 一般思路是蠻力演算法,兩兩求n個點之間的距離並比較,得出最大距離,時間複雜度為o n 2 優化演算法是採用分治的思想,將n個點先按照 x 軸的座標的中值 x mx 平均分為左右兩組,分別求出 xl 和 xr 中的最近點對的距離,因為最近...

尋找最近點對

一維的數很簡單,先排序,再掃瞄已排好的數,相鄰兩個進行比較即可,時間複雜度為o n log2n n o n log2n 兩維的話 把平面上n個點分成兩部分left和right。假設分別求出left和right兩部分最短距離mindistleft和mindistright,還有一種情況就是點對中乙個點...

尋找最近點對

問題 在空間中有n個點,尋找空間中最近的2個點。法一 遍歷,o n 2 法二 分治演算法 將點分為左右兩半,分別找到最近的2個點,然後考慮交叉位置的點對中的最小距離,在這3者中取最小的那個。o nlogn 步驟 1.按照x軸排序 2.找到中間點,分別進行處理 3.2邊處理完成,將進行 merge 過...