Ruby 最近点算法

Ruby 最近点算法,ruby,algorithm,location,Ruby,Algorithm,Location,我有一个约5000个点(指定为经度/纬度对)的列表,我想找到与用户指定的另一个点最近的5个点 有人能提出一个有效的算法来解决这个问题吗?我是用Ruby实现的,所以如果有合适的库,那就很好了,但我仍然对算法感兴趣 更新:一些人询问了有关该问题的更多具体细节。下面是: 这5000个点大多在同一个城市内。可能会有一些在它之外,但可以安全地假设99%位于75公里半径范围内,所有位于200公里半径范围内 点列表很少改变。为了便于讨论,假设它每天更新一次,我们必须在这段时间内处理几千个请求 您可以通过使用

我有一个约5000个点(指定为经度/纬度对)的列表,我想找到与用户指定的另一个点最近的5个点

有人能提出一个有效的算法来解决这个问题吗?我是用Ruby实现的,所以如果有合适的库,那就很好了,但我仍然对算法感兴趣

更新:一些人询问了有关该问题的更多具体细节。下面是:

  • 这5000个点大多在同一个城市内。可能会有一些在它之外,但可以安全地假设99%位于75公里半径范围内,所有位于200公里半径范围内
  • 点列表很少改变。为了便于讨论,假设它每天更新一次,我们必须在这段时间内处理几千个请求

您可以通过使用a或a对2D空间进行分区来加速搜索,然后在到达叶节点后,逐个比较剩余距离,直到找到最接近的匹配


另请参阅其中提到的两种方法,它们都使用Ruby中的kd树讨论最近邻搜索。

由于您的列表很短,我强烈建议使用暴力。只需将所有5000与用户指定的点进行比较。是O(n),你会得到报酬的

除此之外,四叉树或Kd树是空间细分的常用方法。但在你的例子中,你最终会在树中做线性数的插入,然后是恒定数的对数查找。。。这是一种浪费,因为你最好只是做一个线性的距离比较,然后用它来做

现在,如果你想找到N个最近的点,你可以根据计算出的距离进行排序,然后取前N个,但这仍然是O(N log N)ish


编辑:值得注意的是,如果您要为多个查询重用点列表,则构建空间树是值得的。

既然您有那么几个点,我建议您进行暴力搜索,效果是使用一个
O(n^2)
操作,使用
n=5000
,,或者对一个合适的算法进行大约25/200万次迭代,并且只存储相关的结果。这在C语言中的执行时间不到100毫秒,所以我们在Ruby中最多看一两秒钟

当用户选择一个点时,您可以使用存储的数据以恒定的时间给出结果


编辑我重新阅读了您的问题,似乎用户提供了自己的最后一点。在这种情况下,每次用户提供一个点时,通过集合进行
O(n)
线性搜索会更快。

对于5000个节点,我会计算每个节点的单独x+y距离,而不是直线距离


对该列表进行排序后,如果第5个节点的x+y为38,则可以排除x或y距离大于38的任何节点。这样,就可以排除许多节点,而不必计算直线距离。然后用蛮力计算剩余节点的直线距离。

你可以使用曼哈顿距离(按纬度缩放)得到距离的快速上界估计值,这应该足以拒绝99.9%不接近的候选节点(编辑:从那时起,你告诉我们他们很接近。在这种情况下,你的度量应该是距离的平方,根据Lars H的评论)。 考虑这等同于拒绝在球面矩形包围盒之外的任何东西(作为圆包围盒的近似)。 我不使用Ruby,所以这里是带有伪代码的算法:

initialize Dmin with the fifth-smallest D from the first five points in list
for point X in list:
    if D(X,P) <= √2 * Dmin:
        insert the tuple (X,D) in the priority-queue of candidates
        if (Dmin>D): Dmin = D
# after first pass, reject candidates with D > √2 * Dmin (use the final value of Dmin)
# ...
# then a second pass on candidates to find lowest 5 exact distances
让您的参考点p(pa,po)和另一点X(xa,xo)的纬度和经度。 预计算ka,纵向距离的纬度比例因子:ka(=cos(pa in°)。(严格来说,ka=常数是P附近的线性近似值。)

然后距离估计器是:
D(X,p)=ka*| xa pa+|xo po |=ka*da+do

式中| z |表示绝对值(z)。最坏情况下,该值高估了真实距离的一个系数√2(当da==do时),因此我们考虑如下:

进行连续搜索并保留Dmin,这是曼哈顿距离估计值第五小的比例。 因此,您可以预先拒绝D(X,P)>√2*Dmin(因为它们必须至少比√((ka*da)²+do²)-这将减少99.9%的分数)。 用D(X,P)保留所有剩余候选点的列表√2*Dmin(使用Dmin的最终值) # ... #然后,对候选人进行第二次检查,以找到最低的5个精确距离
这些算法不容易解释,因此我只给您一些正确方向的提示。您应该寻找Voronoi图。使用Voronoi图,您可以轻松地在O(n^2 logn)时间内预计算图形,并在O(logn)时间内搜索最近点

预计算是在晚上用cron作业完成的,搜索是实时的。这符合您的规范

现在,您可以保存5000个点中每个点的k个最接近点对,然后从Voronoi图中最近的点开始搜索剩余的4个点

但请注意,这些算法并不容易实现

一个好的参考是:

  • 德伯格:《计算几何算法应用》(2008)第7.1章和第7.2章

如果您需要使用不同的用户输入位置重复此操作多次,但不想实现四叉树(或找不到库实现),则可以使用一种相当直观的位置敏感哈希(类似)方法:

  • 取(x,y)对,创建两个列表,一个是(x,i),一个是(y,i),其中i是点的索引
  • 对两个列表进行排序
那么,w