NearestNeighbor 最近点对

问题

求出二维平面坐标系上nn个点中最近两点的距离。

解法

遍历所有顶点求出任意两点间的距离,从而求出最近距离,该方法的时间复杂度为O(n2)O(n^2),本文介绍一个更快的算法。

通过分治法将二维平面坐标系上的nn个顶点作为一个区域ss,可知该区域的xx坐标范围为[xmin,xmax][ x_{min}, x_{max} ]yy坐标范围为[ymin,ymax][ y_{min}, y_{max} ]。如下图所示:

在区域ss中选取xx坐标最接近xmin+xmax2\frac{x_{min} + x_{max}}{2}的顶点pp(若存在多个相同坐标的顶点pp,选择xx轴最小的),用垂直于xx轴,xx坐标为xpx_{p}的直线将该区域划分为左右两个子区域leftleftrightright。顶点pp不属于leftleftrightright任意区域。对两个子区域,类似的继续进行划分,直到区域中顶点的数量n3n \leq 3

当一个区域中的顶点数量n3n \leq 3时,可以直接求出这些顶点中的最近两点距离distmindist_{min}。对于两个相邻子区域,虽然已知两个子区域内的最近两点距离,但两个相邻子区域合并后的最近两点距离仍然不确定。

当合并两个相邻子区域leftleftrightright时,设两个子区域的最近两点距离分别为distleft,distrightdist_{left}, dist_{right},分割两个区域的中点为pp。对于leftleft区域中的任意顶点aa,若其满足

xaxpdistleftyaypdistleft\begin{matrix} \lvert x_a - x_p \rvert \leq dist_{left} \\ \lvert y_a - y_p \rvert \leq dist_{left} \end{matrix}

aapp有可能是最近点对,不满足该条件的aapp必然不是最近点对。

通过直接判断x,yx, y轴可以避免计算二维平面上两点距离时的乘法运算,最终只需要计算出pp与它周围最近的的一部分顶点的距离即可。算出点pp与它周围顶点的距离distapdist_{ap}。同理,对于区域rightright中的所有满足下列条件的顶点bb

xbxpdistrightybypdistright\begin{matrix} \lvert x_b - x_p \rvert \leq dist_{right} \\ \lvert y_b - y_p \rvert \leq dist_{right} \end{matrix}

pp与这些顶点的距离为distbpdist_{bp}。在pp周围的顶点,以及left,rightleft, right区域中的最近点对,在这些点对中选出距离最近的两点。重复上述操作,递归合并相邻两区域,最终可以求出nn个点中的最近两点距离。

该算法的时间复杂度为O(log2n)O(log_2 n)

源码

NearestNeighbor.h

NearestNeighbor.cpp

测试

NearestNeighborTest.cpp

Last updated