【问题标题】:Optimize bruteforce solution of searching nearest point优化搜索最近点的蛮力解决方案
【发布时间】:2018-03-23 06:45:03
【问题描述】:

我有散布在平面上的非空集合点,它们由它们的坐标给出。 问题是快速回复此类查询:

给我你的集合中离点 A(x, y) 最近的点

我目前的解决方案伪代码

query( given_point )
{
  nearest_point = any point from Set
  for each point in Set
    if dist(point, query_point) < dist(nearest_point, given_point)
      nearest_point = point
  return nearest_point
}

但是这个算法很慢,复杂度是O(N)

问题是,是否有任何具有预先计算的数据结构或棘手的算法可以显着降低时间复杂度?我至少需要O(log N)

更新

距离是指欧式距离

【问题讨论】:

    标签: algorithm computational-geometry


    【解决方案1】:

    您可以使用kd-tree 获得 O(log N) 时间。这就像一棵二叉搜索树,只是它先在 x 维上分割点,然后在 y 维上,然后再在 x 维上,以此类推。

    如果你的点是均匀分布的,你可以实现O(1)查找,方法是把点分箱到大小均匀的盒子里,然后搜索查询点所在的盒子和它的八个相邻的盒子。

    很难从 Voronoi 图做出有效的解决方案,因为这需要您解决确定查询点位于哪个 Voronoi 单元格的问题。大部分时间这涉及构建 R*-tree 来查询Voronoi 单元的边界框(O(log N) 时间),然后执行多边形中的点检查(O(p) 中的点数多边形的周长)。

    【讨论】:

    • 是的,kd-tree 是解决这个问题的方法。
    • 感谢您的回复,我找到了 kd-trees 库。现在尝试自己实现kd-tree
    • @oybek:如果您在 C++ 环境中,我发现 nanoflann 可以很好地工作。 Python 在 SciPy 中有一个实现。不确定其他语言。
    • @Richard:目前我需要 Java 中的算法,在 github 中找到了实现 kd-tree 和其他非标准结构的 repo
    【解决方案2】:

    您可以将网格划分为多个小部分:

    根据点数和网格大小,您可以选择有用的划分。让我们假设一个 1000x1000 像素的屏幕,填充了随机点,均匀分布在表面上。

    您可以将屏幕分成 10x10 的部分并制作地图 (roughX, roughY)->(List ((x, y), ...)。对于某个点,您可以查找同一单元格中的所有点并且 - 由于该点可能更接近于相邻单元格的点而不是同一单元格中的极值点,因此周围的单元格,甚至可能是 2 个单元格。这会将搜索范围减少到 16 个单元格。

    如果您在同一单元格/层中没有找到点,请将搜索扩展到下一层。

    如果您碰巧在下一层中找到下一个邻居,则必须将搜索范围扩大到每一层的附加层。如果点太多,请选择更精细的网格。如果点数很少,请选择更大的网格。请注意,用一条线连接到红色的两个绿色圆圈与红色圆圈的距离相同,但一个位于第 0 层(同一单元格),而另一个位于第 2 层(下一个单元格的下一个)。

    【讨论】:

    • 是的,我考虑过分割区域并找到“voronoi 图”数据结构,想法是为每个点构建一个多边形,其中包含仅给定点的最近点
    • 嗯 - 这取决于点是添加到图表中还是删除,您获得查询的频率和数量。要生成粗略的网格,您只需要舍入和除法以及点列表的 2dim 数组。因此,对于 (x,y) 847,134,您会将点存储在 (84,13) 并从 x:82 到 86 和 y:11 到 15 进行搜索。找到最近的邻居后,您也可以将该值存储在结果中地图,以避免第二次搜索,即使在较小的相对邻居子集中。
    • @oybek:很难使用 Voronoi 图。我已更新我的答案以对此发表评论。
    • @userunknown:如果这些点“均匀分布在表面上”,那么您就知道这些点的密度以及它们之间的预期距离。从中您可以选择最佳网格大小。
    【解决方案3】:

    如果不进行预处理,您肯定需要花费 O(N),因为您必须在返回最接近的点之前查看每个点。

    您可以在这里查看Nearest neighbor search,了解如何解决此问题。

    【讨论】:

      猜你喜欢
      • 2014-03-29
      • 1970-01-01
      • 1970-01-01
      • 2022-07-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-08
      • 2021-10-21
      • 2021-04-20
      相关资源
      最近更新 更多