自己对照《算法分析与设计》书上的伪代码用python实现的,个人原创,欢迎指导借鉴。
书本伪代码:
不多说,直接上干货:
import math
# 求两点之间距离的函数
def distance(a, b):
return math.sqrt((b[0] - a[0]) ** 2 + (b[1] - a[1]) ** 2)
# 蛮力法求一组数据中最近的两点(处理点的个数小于等于3的情形)
def manli_nearest_points(points):
n = len(points)
dmin = distance(points[0], points[1])
p1 = points[0]
p2 = points[1]
for i in range (0,n-1):
for j in range (i+1,n):
if dmin > distance(points[i], points[j]):
dmin = distance(points[i], points[j])
p1 = points[i]
p2 = points[j]
return p1, p2, dmin
# 对一组点按照x坐标的升序排列
def paixu_x(points):
n = len(points)
for i in range (0, n-1):
for j in range (0, n-1-i):
if points[i][0] > points[i + 1][0]:
tp = points[i]
points[i] = points[i + 1]
points[i + 1] = tp
return points
# 对一组点按照y坐标的升序排列
def paixu_y(points):
n = len(points)
for i in range (0, n-1):
for j in range (0, n-1-i):
if points[i][1] > points[i + 1][1]:
tp = points[i]
points[i] = points[i + 1]
points[i + 1] = tp
return points
# 分治法求解最近点对
def efficient_closest_pair(p,q):
n = len(p)
if n <= 3:
x1, x2, dmin = manli_nearest_points(p) # 点集中的点的个数小于3的时候直接用蛮力法求
else:
pl = {} # 创建空的点集用来保存点
ql = {}
pr = {}
qr = {}
s = {}
for i in range(0, int(n/2)): # 将p和q的前n/2个点复制到pl和ql
pl[i] = p[i]
ql[i] = q[i]
for i in range(int(n/2),n): # 将p和q中余下的点复制到pr和qr
pr[i-int(n/2)] = p[i]
qr[i-int(n/2)] = q[i]
xl1, xl2, dl = efficient_closest_pair(pl, ql) # 递归调用分治法,保存左边内部的最近点对和最近距离
xr1, xr2, dr = efficient_closest_pair(pr, qr) # 递归调用分治法,保存右边内部的最近点对和最近距离
if dl <= dr: # 比较左右两边的最近距离,保存较小者和对应的点对
x1, x2, dmin = xl1, xl2, dl
else:
x1, x2, dmin = xr1, xr2, dr
m = p[int(n/2)][0] # 取中线
num = 0 # 用来记录中线两端距离为dmin内的点的个数
for i in range (0, n): # 保存中线两端距离为dmin内的点到s集合中
if abs(q[i][0] - m) < dmin:
s[num] = q[i]
num = num + 1
dminsq = dmin**2
for i in range (0, num-1): # 遍历s,寻找其中的最近点对
k = i + 1
while k <= num - 1 and (s[k][1]-s[i][1])**2 < dminsq: # 对s内的点,只需要比较s点上下dmin距离内的点
t = (s[k][0]-s[i][0])**2+(s[k][1]-s[i][1])**2
if t < dminsq:
x1, x2, dmin = s[i], s[k], math.sqrt(t)
k = k + 1
return x1, x2, dmin
def main():
points = [(1, 1), (2, 3), (3, 4), (4, 5), (5, 6), (6, 4), (7, 3), (8, 1), (5, 1), (10, 8),
(20, 8), (8, 7), (8, 8), (18, 4), (2, 5), (6, 10)]
p = paixu_x(points) # 按照分治法的要求对点集进行排序
q = paixu_y(points)
p1, p2, dmin = efficient_closest_pair(p,q) # 将排序好的点集输入分治法函数
print("最近的两个点的坐标为:", p1, p2, "最近距离为:", dmin)
if __name__ == "__main__":
main()