查找矩形内所有点的快速算法

时间:2015-12-14 15:22:40

标签: algorithm computational-geometry

给定2D空间中的一组不同点,以及一个矩形(所有四个点的坐标,与xy轴平行的边),如何快速找到矩形内的哪些点?

我对通过所有点并看到哪个点位于矩形内的基本解决方案不感兴趣。我正在寻找的算法是每个矩形的快速查询时间。

我不在乎我在预处理步骤中花费了多少时间。我所关心的是,在处理完数据之后,我获得了一个有用的结构,它为每个矩形提供了快速的查询时间。

我知道例如我可以计算O(logN)中矩形内有多少个点。这是有效的,因为我在开始时做了很多繁重的处理,然后每次用新的矩形查询处理过的数据,并在logN时间内得到一个新的计数。我正在寻找一种类似的算法来查找实际的点,而不仅仅是它们的数量。

5 个答案:

答案 0 :(得分:8)

经典答案是kD树(在这种情况下是2D树)。

对于一个简单的替代方案,如果你的点分布足够均匀,你可以尝试网格化。

为方形网格选择单元格大小(如果问题是各向异性的,请使用矩形网格)。将每个点分配给包含它的网格单元,存储在链表中。执行查询时,查找与矩形重叠的所有单元格并扫描它们以遍历其列表。对于部分覆盖的单元格,您需要执行矩形点测试。

尺寸的选择很重要:太大会导致需要测试太多的点;太小会导致太多空单元格。

答案 1 :(得分:3)

您正在寻找kd-tree range search或范围查询。

  • 当有一组不断变化的点时,四叉树(或八角树或十六树......)会更好,但你希望分布是均匀的。不需要进一步的平衡步骤,因为树的结构是固定的。
  • kd-tree在固定的点集上表现更好,即使分布不均匀。当点集发生变化时,很难(但并非不可能)进行自平衡步骤。
  • AABB树(或脂肪AABB树)提供了一种快速测试重叠形状的方法,而不仅仅是点。 AABB树偶尔需要一些平衡。当包含不断移动的对象时,常见的方法是使用“fat AABB-s”,因此您不必在每个帧中更新树。
  • 仅按一个轴进行排序并使用二分搜索(类似于abelenky建议,但我认为进行第二次二分搜索没有意义)是一个简单而优雅的解决方案,但是当你按照X轴,并且所有点都在与Y平行的线上。您必须对二进制搜索与X匹配的点进行线性过滤。时间复杂度最差情况O(n),但这是最坏的情况经常发生。

所有这些算法以平均O(log n + k)运行查询,其中k是匹配点的计数。

与Yves建议的一样,网格化可以在O(k)时间内执行范围搜索,但仅限于查询矩形的大小有界时。这是他们在particle simulations中经常做的事情。即使输入集没有限制,也可以使用网格化 - 只需根据网格坐标的哈希值对固定数量的桶进行计数。但是如果查询矩形可以是任意大小,那么网格化是不行的。

答案 2 :(得分:1)

您可以将点数分组。如果扇区完全在给定矩形内或外,则其中的所有点也在内或外。如果扇区部分存在,则必须在O(n)中搜索该扇区中的点以检查它们是否在矩形中。寻找k-d tree搜索。

答案 3 :(得分:1)

除了其他答案,您还可以查看莫顿代码(z顺序曲线排序)。

在您的情况下,即静态数据,您甚至可以将整个点数据表示为数组。

https://en.wikipedia.org/wiki/Z-order_curve

本文还有一个相当复杂的不同“多维访问方法”的时间表 - http://www.cc.gatech.edu/computing/Database/readinggroup/articles/p170-gaede.pdf

答案 4 :(得分:0)

我认为你应该将你的积分存储在quadtree。我没有弄清楚细节,但它应该允许基本上做类似于二元搜索的东西,直接产生矩形内的点。

如果你的点是聚类的,即在一个小区域内存在包含许多点的聚类,而其他区域包含没有或非常少的点,R-tree可能会更好。

我认为运行时复杂度应为O(logN)。