快速算法在平面上找到离给定点最近的 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 个点的主要内容,如果未能解决你的问题,请参考以下文章

在二维平面中找到K最近点到点P.

寻找附近点的算法?

平面最近点对问题

Luogu 1429 平面最近点对 | 平面分治

平面最近点对(加强版)

找到离原点最近的 100 颗恒星的算法