寻找附近点的算法?

Posted

技术标签:

【中文标题】寻找附近点的算法?【英文标题】:Algorithm for finding nearby points? 【发布时间】:2010-10-24 17:06:02 【问题描述】:

给定一组具有 x,y 坐标的数百万个点,选择什么算法可以快速找到距某个位置最近的 1000 个点?这里的“快速”是指在家用电脑上大约 100 毫秒。

蛮力意味着进行数百万次乘法然后对它们进行排序。虽然即使是简单的 Python 应用程序也可以在不到一分钟的时间内完成,但对于交互式应用程序来说仍然太长了。

点的边界框是已知的,因此可以将空间划分为一个简单的网格。但是这些点的分布有些不均匀,所以我怀疑大多数网格方块会是空的,然后突然其中一些会包含大部分点。

编辑:不一定要准确,实际上可能很不准确。例如,如果前 1000 名实际上只是前 2000 名中的一些随机点,那也没什么大不了的。

编辑:点集很少改变。

【问题讨论】:

是否必须准确,或者是否也可以,例如选择的 1000 个中有 900 个是最接近的 1000 个? 点的集合是固定的吗?在一组点发生变化之前,您会为几个不同的位置获取最接近的 1000 个点吗? 【参考方案1】:

用quadtree怎么样?

你将区域划分为矩形,如果区域的点密度低,矩形就大,如果区域的点密度高,矩形就小。您递归地将每个矩形细分为四个子矩形,直到矩形足够小或包含足够少的点。

然后您可以开始查看该位置附近矩形中的点,然后向外移动直到找到 1000 个点。

这方面的代码可能会有些复杂,所以也许您应该先尝试使用简单的网格,看看它是否足够快。

【讨论】:

【参考方案2】:

四叉树很好,但BSP trees 保证在 O(log n) 时间内运行。我认为四叉树需要有限的边界体积,并且在某些退化的情况下四叉树会惨遭失败,例如当大量点占据相同相对较小的空间时。

话虽如此,四叉树可以说更容易实现,并且在大多数常见情况下非常有效。这是 UPS 在其路由算法中使用的,因为它的缺点在实践中不会造成重大问题,可能是因为城市往往分布在感兴趣的区域。

【讨论】:

【参考方案3】:

您想使用四叉树或 RTree 之类的结构。这些是多维索引结构。

关键是使用良好的“空间填充曲线”,这有助于定义点的接近度。简单的空间填充曲线是 Zorder,但您可能对希尔伯特曲线之类的东西更感兴趣。

http://en.wikipedia.org/wiki/Space_filling_curve

我不知道这些东西的任何预打包实现。我最近实现了自己的二维 RTree,仅支持批量加载和搜索(通过提供的边界框)。

这里的一个缺点是您的点必须包含在有限区域中。知道有一些空间填充曲线适用于非有限空间,但我对它们一无所知。

【讨论】:

这些空间填充曲线是我思考问题的一个惊人的新鲜观点,非常感谢!【参考方案4】:

除了 QuadTree 和 BSP 树建议之外,您还应该查找 nearest neighbour searching。算法的选择取决于您添加到基础数据集的频率。如果您经常添加和删除,那么树解决方案会更好。如果数据更加静态,则最近邻搜索和 voronoi 图可以更快并且可以更好地扩展。

【讨论】:

【参考方案5】:

如果点集很少发生变化,您还可以考虑使用 voronoi 图。我不确定这是否有助于更快地找到 first 点,但它应该更容易找到接下来的 999 个点。

【讨论】:

【参考方案6】:

我假设这些点位于数据库或某个可搜索的索引位置?如果是这样,它应该很快。从给定点,您可以在 x 和 y 轴上有一个范围并获取该范围内的所有位置(即指定最左上角 x(a) 和 y(b) 以及最右下角 x(c) 和 y (d))。

然后查询其中 y >= b AND y = a AND x

然后您可以将该范围增加(或减少,如果结果很大)z,直到结果集中的点数 >= 1000。通过一些试运行,您应该能够得出标准偏差和其他统计数字将帮助您确定开始时矩形的大小。你的程序也可以根据它得到的结果来调整它自己。

一旦你有了粗略的数据集,它就可以通过非常简单的数学计算出每个点与源点之间的距离。

【讨论】:

它们不在关系数据库中,而且我记得读过像 mysql 这样的关系数据库在这种情况下一次只能使用一个索引。 这听起来是个好主意。如果你的索引设置正确,数据库软件有一些很好的算法可以让这些查询变得非常快。如果它们不在数据库中,请编写一个快速脚本将它们放在一个中,并至少对其进行测试。它不一定是最快的解决方案,但它可能是最快的实现,而且你的时间比几个 CPU 周期更有价值,对吧? 仅使用一维索引不能有效地满足对两个不同属性的范围查询。关系数据库并不神奇。【参考方案7】:

我知道如果你想要真正快速的结果,我知道它不是最快的.它查找靠近 a 坐标的位置并按距离返回它们。

我希望它可以帮助某人:)

CREATE PROCEDURE [dbo].[getstores] @lat float,  @lng float AS
DECLARE @radius float, @DegToRad float
SET @DegToRad = 57.29577951
SET @radius = 25000
SELECT TOP 10
    name
    ,sto_lat
    ,sto_lng
    ,postcode
    ,ROUND((ACOS((SIN(@lat/57.2958) * SIN(sto_lat/@DegToRad)) +(COS(@lat/@DegToRad) * COS(sto_lat/@DegToRad) *COS(sto_lng/@DegToRad - @lng/@DegToRad))))* 6387.7, 2) AS distance
FROM store
WHERE (sto_lat >= @lat - (@radius/111))
And (sto_lat <= @lat + (@radius/111))
AND (sto_lng >= @lng - (@radius/111))
AND (sto_lng <= @lng + (@radius/111))
AND (
     ISNUMERIC(sto_lat) = 1
    AND
    ISNUMERIC(sto_lat) = 1
)
ORDER BY distance

注意:我已经说过这不是解决这个问题的最佳解决方案,可能只是像我这样在谷歌上发现这个问题的人

【讨论】:

以上是关于寻找附近点的算法?的主要内容,如果未能解决你的问题,请参考以下文章

dijkstra算法:寻找到全图各点的最短路径

数据库/地理位置。寻找附近的人[关闭]

VoiceOver 正在寻找附近的可访问元素来阅读?

梯度下降——寻找那个最优解

匈牙利算法dfs模板 [二分图][二分图最大匹配]

数值算法:无约束优化之一维搜索方法之划界法寻找极小点上下界