问题
求出二维平面坐标系上n个点中最近两点的距离。
解法
遍历所有顶点求出任意两点间的距离,从而求出最近距离,该方法的时间复杂度为O(n2),本文介绍一个更快的算法。
通过分治法将二维平面坐标系上的n个顶点作为一个区域s,可知该区域的x坐标范围为[xmin,xmax],y坐标范围为[ymin,ymax]。如下图所示:
在区域s中选取x坐标最接近2xmin+xmax的顶点p(若存在多个相同坐标的顶点p,选择x轴最小的),用垂直于x轴,x坐标为xp的直线将该区域划分为左右两个子区域left和right。顶点p不属于left或right任意区域。对两个子区域,类似的继续进行划分,直到区域中顶点的数量n≤3。
当一个区域中的顶点数量n≤3时,可以直接求出这些顶点中的最近两点距离distmin。对于两个相邻子区域,虽然已知两个子区域内的最近两点距离,但两个相邻子区域合并后的最近两点距离仍然不确定。
当合并两个相邻子区域left和right时,设两个子区域的最近两点距离分别为distleft,distright,分割两个区域的中点为p。对于left区域中的任意顶点a,若其满足
∣xa−xp∣≤distleft∣ya−yp∣≤distleft 则a与p有可能是最近点对,不满足该条件的a与p必然不是最近点对。
通过直接判断x,y轴可以避免计算二维平面上两点距离时的乘法运算,最终只需要计算出p与它周围最近的的一部分顶点的距离即可。算出点p与它周围顶点的距离distap。同理,对于区域right中的所有满足下列条件的顶点b:
∣xb−xp∣≤distright∣yb−yp∣≤distright 点p与这些顶点的距离为distbp。在p周围的顶点,以及left,right区域中的最近点对,在这些点对中选出距离最近的两点。重复上述操作,递归合并相邻两区域,最终可以求出n个点中的最近两点距离。
该算法的时间复杂度为O(log2n)。
源码
NearestNeighbor.h
NearestNeighbor.cpp
测试
NearestNeighborTest.cpp