2d圆最近邻的最佳动态数据结构

时间:2014-02-23 19:23:02

标签: algorithm language-agnostic computational-geometry

标题是大多数问题。我有一组圆圈,每个圆圈由中心C和半径r给出。两个圆之间的距离是它们中心之间的欧氏距离减去它们的半径。对于圆圈a和b,

  

d_ab = | C_a - C_b | - r_a - r_b。

注意如果圆圈重叠,这可能是负面的。

那么找到集合中给定圆的最近(最小距离)邻居的最快数据结构是什么?

必须支持添加和删除以“任意顺序交错”的“查找最近”查询的圆圈。事先没有人知道该集的几何分布。

这将是系统的核心,其中典型的圈数为50,000,并且将需要成千上万的查询,插入和删除,理想情况是高端的用户交互速度(一秒或更短)平板电脑设备。

最近邻居已被研究过死亡,但这个带圆圈的版本似乎有些难度。

我看过kd-trees,四棵树,r-trees以及这些的一些变种。关于哪些可能是最好的尝试以及新建议的建议都将是一个非常好的帮助。

4 个答案:

答案 0 :(得分:5)

Cover trees是邻近结构的另一种可能性。它们不支持删除(?),但您可以在后台软删除和重建以防止垃圾堆积,这对于其他结构可能是一种有用的技术。

从2D圆问题到3D点问题的减少,其中有一个像这样的时髦指标。 (您命名的邻近结构应该是可适应的。)将以(x,y)为中心的圆以半径r映射到点(x,y,r)。将矢量(dx,dy,dz)的长度定义为sqrt(dx ** 2 + dy ** 2)+ abs(dz)。这导致了一个指标。要找到距离中心最近的圆(x,y)(查询圆的半径不相关),请在(x,y,R)处进行邻近搜索,其中R大于或等于最大半径一个圆圈(可以修改你的邻近结构,这样就不必跟踪R)。

根据我在点上实现kd-trees和Voronoi图的经验,从头开始实现kd-tree将更加容易。即使你重复使用其他人强大的几何原语(如果你走这条路线,请尽量保存你的理智),Voronoi /点位置的退化边缘情况需要时间才能正确。

答案 1 :(得分:2)

我建议使用KD-Tree或其他允许O(log N)最近邻居的其他启发式方法。而不是使用单个点和半径来表示圆。在圆圈上使用k等距点,加上圆心,否则可能会出现大圆圈内的小圆圈问题。它与使用k个顶点的正多边形来表示圆圈的想法相同。然后可以取一个顶点并找到它的最近邻居(忽略同一圆上的顶点),以找到基于最近的正多边形的最近圆的近似值。

表演如下:

创建KD树:O(kN log kN)

删除/添加圆到KD树:O(k log kN) - 在KD树中添加或删除圆圈的所有k点

最近圆查询(圆圈):O(k log kN) - 这是通过首先去除圆的所有k个点(O(k log kN))来完成的,因为找出圆的最近邻居不出所料,圆圈本身并不是非常有用。然后,对于圆中的每个k点,找到最近的邻居(O(k log kN))。一旦找到最近邻居,实际最近的(在某个误差范围内)是具有最小距离的那个(在根据点和半径计算真实距离之后)(O(1))。

如果您希望快速或k = sqrt(N),我建议使用k = log(N),如果您更喜欢它是准确的。

另外,我可能没有考虑过导致问题的特殊情况,所以要小心。

答案 2 :(得分:1)

如果保证圆的半径不大,那么至少最大半径(R)明显小于圆所在的区域,我想它可以用标准空间分区和最近邻搜索覆盖

当搜索与给定圆距离最小的集合中的圆时,给定圆的半径无关紧要(距离定义。)因此,如果仅将中心(点)与圆的集合进行比较,则相同

这样就足以在空间分区结构中存储一组圆圈,只有中心(一组点)。圆形添加和删除以标准方式完成。找到给定点的最近圆可以分两步完成:

  • 找到距离给定点最近的中心P.说出圆心C,中心c和半径r。
  • 靠近P的圆心,按您的距离,只能在P内环半径为r,外半径为R-d(P,c)。只需搜索与该环相交的分区即可。

通过组合这两个步骤可以优化搜索。在第一步中,已经访问了一些感兴趣的分区。通过存储访问的分区,并在这些分区中找到最小距离的圆圈,可以减少第二步搜索。

答案 3 :(得分:0)

感谢@David Eisenstadt提出的3D搜索结构。这是最佳答案的一部分,但不需要他的奇怪指标。

关键是详细了解最近邻搜索的工作原理。我会把它显示为四分之一。 k = 3的Kd树是相似的。这是伪代码:

# Let nearest_info be a record containing the current nearest neighbor (or nil 
# if none yet) and the distance from point to that nearest neighbor.
def find_nearest_neighbor(node, target, nearest_info)
  if node is leaf
    update nearest_info using target and the points found in this leaf
  else
    for each subdivision S of node
      if S contains any point P where dist(P,T) < nearest_info.distance,
        find_neareast(S, target, nearest_info)
      end
    end
  end
end

完成此操作后,nearest_info包含最近邻居及其距离。

关键是if S contains any point P where dist(P,T) < nearest_info.distance。在描述圆圈的(x,y,r)三元组的3d空间中,我们有

def dist(P,T)
  return sqrt( (P.x - T.x)^2 + (P.y - T.y)^2 ) - P.r - T.r 
end

这里P是八角形长方体的八分圆中的任意点。如何考虑长方体中的所有点?请注意,对于给定的搜索,T的所有组件都是有效固定的,因此如果我们将目标写为常量点(a, b, c),它会更清楚:

def dist(P)
  return sqrt( (P.x - a)^2 + (P.y - b)^2 ) - P.r
end

我们完全遗漏了c = T.r,因为在算法完成后可以从最小距离中减去它。换句话说,目标的半径不会影响结果。

有了这个,很容易看出我们需要获得最小距离的P是关于x和y以及最大代表半径最接近目标的欧几里德。这非常容易且快速计算:2d点矩形距离和1d max操作。

事后看来,这一切都很明显,但从正确的角度来看它需要一段时间。谢谢你的想法。