凸包問題的分治演算法及python實現
阿新 • • 發佈:2019-02-18
利用分治思想處理凸包問題。
劃分:將點集S中的資料按橫座標排序,選出橫座標最小的點A和縱座標最小的點B,AB的連線將S劃分為兩個子集,位於(AB) 上方的集合S1和位於(BA) 上方的集合S2。
遞迴求解:遞迴呼叫演算法求S1的凸包和S2的凸包,遞迴演算法中找出S1中使∆ABC面積最大的點C,則點C一定位於S1的凸包上,繼續以點AC和CB作為連線劃分S1。
合併:通過上述方法找到的凸包上的點直接合並,最後使用蠻力演算法中的輸出方法逆序輸出點即可。
隨機點集S生成部分與蠻力演算法相同
分治演算法中遞迴部分程式碼如下:
def dealleft(first,final,lis,temp):
#temp用來標記位於凸包上的點
max=0
index=-1
#處理first到final的上方,得到使first,final,i 三點組成的三角形面積最大的點i
if first<final:
for i in range(first,final):
#獲得first,final,i 的座標
firstcoordinate=lis[first]
finalcoordinate=lis[final]
icoordinate=lis[i]
firstx=firstcoordinate[0 ]
firsty = firstcoordinate[1]
finalx=finalcoordinate[0]
finaly = finalcoordinate[1]
ix=icoordinate[0]
iy = icoordinate[1]
#計算first,final,i 三點組成的三角形面積
triangle_area=firstx * finaly + ix * firsty + finalx * iy - ix * finaly - finalx * firsty - firstx * iy
if triangle_area>max:
max=triangle_area
index=i
# 處理first到final的下方,得到使first,final,i 三點組成的三角形面積最大的點i
else:
for i in range(final,first):
firstcoordinate = lis[first]
finalcoordinate = lis[final]
icoordinate = lis[i]
firstx = firstcoordinate[0]
firsty = firstcoordinate[1]
finalx = finalcoordinate[0]
finaly = finalcoordinate[1]
ix = icoordinate[0]
iy = icoordinate[1]
triangle_area = firstx * finaly + ix * firsty + finalx * iy - ix * finaly - finalx * firsty - firstx * iy
if triangle_area > max:
max = triangle_area
index = i
if index!=-1:
temp[index]=1
dealleft(first,index,lis,temp)
dealleft(index,final,lis,temp)
接下來是演算法的主程式部分,程式碼如下:
def divide(lis,n):
starttime = datetime.datetime.now()
# temp用來標記位於凸包上的點
temp = {}
# lis_con_new為凸包集合
lis_con_new = []
if n==3:
return lis
for i in range(n):
temp[i]=0
lis_con=copy.deepcopy(lis)
lis_con.sort()
temp[0]=1
temp[n-1]=1
dealleft(0,n-1,lis_con,temp)
dealleft(n-1,0,lis_con,temp)
for i in temp:
if temp[i]==1:
lis_con_new.append(lis_con[i])
endtime = datetime.datetime.now()
print "分治時間---",(endtime - starttime)
return lis_con_new
分治演算法在點集數500、1000、2000、3000、4000的情況下得到演算法執行時間(秒),繪製成如下圖所示折線圖,可以看出在資料集較大的情況下,分治演算法執行時間仍在毫秒水平,保持較好的效能。其中在資料從2000增加至3000的過程中,演算法執行時間有些許減少。