快速算法在平面上找到离给定点最近的 x 个点
Posted
技术标签:
【中文标题】快速算法在平面上找到离给定点最近的 x 个点【英文标题】:Fast algorithm to find the x closest points to a given point on a plane 【发布时间】:2012-02-25 04:38:06 【问题描述】:我想找到一种快速算法,以便找到距离平面上给定点最近的 x 个点。
我们实际上处理的点并不多(在 1,000 到 100,000 之间),但我需要每个点的 x 个最近点。 (其中 x 通常在 5 到 20 之间。)
我需要用 C# 编写它。
更多关于用例的上下文:这些点是地图上的坐标。 (我知道,这意味着我们不完全是在谈论平面,但我希望避免处理投影问题。)在端点附近有很多其他点应该显示为红色,没有太多的点靠近它们的点应显示为绿色。在这两个极端之间,点位于颜色渐变上。
【问题讨论】:
我不确定您要求的算法是否最适合您的用例。也许您可以遍历所有点并计算粗略的密度函数(二维直方图)。然后,您可以根据计算的单元格密度为每个点着色,也可以考虑相邻单元格。 【参考方案1】:您需要的是一种适合在平面上组织点的数据结构。 K-D-Tree 经常用于这种情况。请参阅***上的k-d tree。
在这里,我找到了Geometric Algorithms的一般描述
更新
我将 KD-tree 的 Java 实现移植到 C#。请在 RoboWiki 上查看 User:Ojd/KD-Tree。您可以在那里下载代码,也可以直接从我的homepage 下载CySoft.Collections.zip(仅下载,无文档)。
【讨论】:
爱它,执行速度明显快于下面提到的解决方案。【参考方案2】:对于一个给定的点(不是全部)并且点的数量不是极端的,你可以计算到每个点的距离:
var points = new List<Point>();
Point source = ...
....
var closestPoints = points.Where(point => point != source).
OrderBy(point => NotReallyDistanceButShouldDo(source, point)).
Take(20);
private double NotReallyDistanceButShouldDo(Point source, Point target)
return Math.Pow(target.X - source.X, 2) + Math.Pow(target.Y - source.Y, 2);
(我用过 x = 20)
计算是基于双打的,所以 fpu 应该能够在这里做得不错。 请注意,如果 Point 是类而不是结构,您可能会获得更好的性能。
【讨论】:
更快:不用 Math.Sqrt,您似乎不需要知道确切的距离 :) @vanhelgen true,让我们让它更快 为什么还要在这里调用 Math.pow() 呢? double dx = target.x - source.x;双 dy = target.y - source.y;返回 dx<i>dx + dy</i>dy;
这种方法效率很低。使用 kd 树【参考方案3】:
为了提高效率。假设距离为k。取所有 x 坐标在 x-k 和 x+k 之间的点。类似地,y-k 和 y+k。所以你已经删除了所有多余的坐标。现在将距离设为 (x-x1)^2 + (y-y1)^2。在它们上创建一个包含 k 个元素的最小堆,如果新点
【讨论】:
【参考方案4】:你需要创建一个距离函数,然后计算每个点的距离并对结果进行排序,取第一个x。
如果结果必须 100% 准确,那么您可以使用标准距离函数:
d = SQRT((x2 - x1)^2 + (y2 - y1)^2)
【讨论】:
不需要使用sqr root,您可以根据dx2 + dy2进行排序 其实也可以按abs(dx) + abs(dy)排序 @DarenThomas:哇,这可能是最快的了。以上是关于快速算法在平面上找到离给定点最近的 x 个点的主要内容,如果未能解决你的问题,请参考以下文章