Algorithm 二维圆最近邻的最佳动态数据结构

Algorithm 二维圆最近邻的最佳动态数据结构,algorithm,language-agnostic,computational-geometry,Algorithm,Language Agnostic,Computational Geometry,题目是最主要的问题。我有一组圆,每个圆的中心C和半径r。两个圆之间的距离是它们中心之间的欧几里德距离减去半径。对于圆a和b d|ab=|C|a-C|b |-r|u a-r|b 注:如果圆圈重叠,则可能为负值 那么,在集合中查找给定圆的最近(最小距离)邻居的最快数据结构是什么 必须支持添加和删除带有以任意顺序交错的“查找最近的”查询的圆。事先对集合的几何分布一无所知 这将是一个系统的核心,在这个系统中,一个典型的圆圈数是50000个,需要10个成千上万的查询、插入和删除,理想的情况是在高端平板设备

题目是最主要的问题。我有一组圆,每个圆的中心C和半径r。两个圆之间的距离是它们中心之间的欧几里德距离减去半径。对于圆a和b

d|ab=|C|a-C|b |-r|u a-r|b

注:如果圆圈重叠,则可能为负值

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

必须支持添加和删除带有以任意顺序交错的“查找最近的”查询的圆。事先对集合的几何分布一无所知

这将是一个系统的核心,在这个系统中,一个典型的圆圈数是50000个,需要10个成千上万的查询、插入和删除,理想的情况是在高端平板设备上以用户交互速度(一秒或更少)进行

最近邻点已经被研究得很透彻了,但是这个带有圆圈的版本似乎有点难

我已经研究了kd树、四叉树、r树以及这些树的一些变体。关于其中哪一个可能是最好尝试的建议,以及新的建议都会非常有帮助。

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

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


根据我在点上实现kd树和Voronoi图的经验,从头开始实现kd树将非常容易。即使你重复使用其他人强大的几何原语(如果你走这条路,请这样做,以保持你的理智),Voronoi/点位置的退化边情况也需要时间来纠正。

如果可以保证圆没有大半径,至少是最大半径(R)比圆所在的区域小得多,比我认为的标准空间分割和最近邻搜索所能覆盖的区域小得多

在一个到给定圆的距离最小的集合中搜索圆时,给定圆的半径并不重要(距离定义)。因为只有圆心(点)与圆集合相比较,它是相同的

这样,只需在空间分区结构中存储三个中心(点集)就足够了。点的圆添加和删除是以标准方式进行的。可分两步找到距给定点最近的圆:

  • 找到离给定点P最近的中心。用圆心C和半径r表示圆C
  • 距离P较近的圆心只能位于P周围的环中,内半径r和外半径r-d(P,c)。搜索与该环相交的分区就足够了

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

我建议使用KD树或其他允许O(logn)最近邻的方法进行以下启发式搜索。而不是使用一个点和一个半径来表示一个圆。在圆本身上使用k个等距点,加上圆的中心,否则您可能会遇到大圆中的小圆的问题。这与使用k个顶点的正多边形表示圆的想法相同。然后,可以选取一个顶点并查找其最近的邻居(忽略同一圆上的顶点),以根据最近的正多边形找到最接近的圆的近似值

表演如下:

创建KD树:O(千牛日志千牛)

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

最近圆查询(圆):O(k对数kN) -这是通过首先删除圆的所有k点(O(k log kN))来实现的,因为发现圆的最近邻点是圆本身并不十分有用。然后,对于圆中的每个k点,找到最近的邻居(O(k log kN))。一旦找到最近邻,实际最近邻(误差在一定范围内)就是距离最小的(基于点和半径计算真实距离后)(O(1))

我建议使用k=log(N),如果您希望它快速,或者使用k=sqrt(N),如果您希望它准确


另外,我可能还没有考虑导致问题的一些特殊情况,所以请注意它们。

感谢@David Eisenstatt提出的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
这里p是八叉树长方体的八分之一中的任意点。如何考虑长方体中的所有点?注意,对于给定的搜索,T的所有组件都是有效固定的,因此,如果我们将目标作为常量点写入(a、b、c),则更清晰:

这里我们省略了
c=T.r
co
def dist(P,T)
  return sqrt( (P.x - T.x)^2 + (P.y - T.y)^2 ) - P.r - T.r 
end
def dist(P)
  return sqrt( (P.x - a)^2 + (P.y - b)^2 ) - P.r
end