最近邻搜索不断变化的线段

时间:2012-01-26 02:44:23

标签: algorithm data-structures kdtree

我有一组线段。我想对它们执行以下操作:

  1. 插入新的细分受众群。
  2. 查找给定点的半径R内的所有线段。
  3. 查找给定点的radium R1中的所有点。
  4. 给定一个线段,找出它是否与任何现有线段相交。确切的交叉点不是必需的(尽管这可能不会简化任何事情。)
  5. 问题是像kd / bd树或BSP树这样的算法是它们假设一组静态点,在我的情况下,点会不断地用新点增加,从而需要重建树。

    哪种数据结构/算法最适合这种情况?

    编辑:接受最简单的答案并解决我的问题。谢谢大家!

4 个答案:

答案 0 :(得分:2)

维护动态树可能没有您想象的那么糟糕。

当您将新的点/线等插入到集合中时,很明显您需要优化当前树,但我无法理解为什么每次都需要从头开始重新构建整个树。正如你所建议的那样,新的实体被添加了。

使用动态树方法,您始终拥有一个有效的树,因此您可以使用树类型支持的快速搜索来查找您提到的几何实体。

针对您的特定问题:

  • 您可以设置动态几何树,其中包含叶元素 维护关联的几何实体(点和线)列表 那片叶子。

  • 当一行插入集合时,应将其推入 与其相交的所有叶元素的列表。你可以做 通过从根遍历树的子集来有效地实现这一点 与该线相交的。

  • 要查找指定径向光晕中的所有点/线,首先需要 找到这个地区的所有树叶。同样,这可以通过遍历来完成 从根所包含的树的子集,或者那个 与光环相交。由于可能存在一些重叠,您需要 检查与这组叶元素相关联的实体 实际上是在光环内。

  • 一旦你在一组叶子元素中插入了一行,你就可以找到 是否通过扫描所有行与另一条线相交 与您刚刚找到的叶子框子集相关联。那你可以 对该子集进行线 - 线交叉测试。

潜在的动态树细化算法,基于与树中每个叶子相关联的实体数量的上限,可能会按以下方式工作:

function insert(x, y)

find the tree leaf element enclosing the new entitiy at (x,y) based on whatever 
fast search algorithm your tree supports

if (number of entities per leaf > max allowable) do

    refine current leaf element (would typically either be a bisection 
    or quadrisection based on a 2D tree type)

    push all entities from the old leaf element list onto the new child element
    lists, based on the enclosing child element

else

    push new entity onto list for leaf element

endif

这种类型的细化策略仅对树进行局部更改,因此在实践中通常非常快。如果您还要从集合中删除实体,您还可以通过在每个叶子上施加最少数量的实体来支持动态聚合,并在必要时将叶子元素折叠到其父元素。

我已经多次使用这种类型的方法使用四叉树/八叉树,我现在无法理解为什么类似的方法不适用于kd-trees等。

希望这有帮助。

答案 1 :(得分:1)

一种可能性是将你的空间分成一个盒子网格 - 在y轴上可能是10,在x轴上可能是10,总共100个。

将这些盒子存放在一个阵列中,这样就很容易/快速地确定相邻的盒子。每个框都将保存一个生活在该框中的线段列表向量。

当您计算一个段的R中的线段时,您只能检查相关的相邻框。

当然,您可以创建多个不同粒度的地图,可能是100 x 100个较小的框。只需考虑设计中的空间与时间和维护权衡。

  • 更新分段位置很便宜:只需按x和y方向的整数除以框大小。例如,如果两个方向的box-size为20,则新坐标为145,30。 145/20 == 7和30/20 == 1,所以它进入方框(7,1),对于一个基于0的系统。

答案 2 :(得分:1)

您可以计算完全填充平面的曲线,而不是插入和删除到树中。这样的曲线将2d复杂度降低到1d复杂度,您将能够找到最近的邻居。你可以找到一些像z曲线和希尔伯特曲线的例子。以下是对我的问题http://en.wikipedia.org/wiki/Closest_pair_of_points_problem的更好描述。

答案 3 :(得分:1)

虽然第2项和第2项3相对容易,使用带有距离检查的简单线性搜索,每插入一行,第4项更复杂。

我倾向于使用约束三角剖分来解决这个问题,其中所有输入线都被视为约束,并且使用最近邻居而不是Delaunay准则来平衡三角测量。这在Triangulations and applications by Øyvind Hjelle, Morten DæhlenJoseph O'Rourkes Computational Geometry in C中得到了很好的介绍。两者都有可用的来源,包括获取所有交叉点的集合。

我过去采取的动态方法如下:

  • 创建包含两个三角形的任意三角剖分(TIN) 围绕数据的范围(当前和未来)。

  • 每个新行

  • 将两个点插入TIN。这可以很快完成 遍历三角形以找到插入点,并替换 三角形基于新点和三个新三角形找到 旧三角。

  • 根据两个终点在TIN中切出一段,保持一个 该部分切割任何先前插入的衬里的点列表。 将交叉点详细信息添加到针对两者存储的列表中 行,并将它们插入TIN。

  • 强制插入的行作为约束

  • 平衡在上述过程中修改的所有相邻三角形对 使用最近邻居标准,并重复直到所有三角形 已经平衡了。

这对于分布不良的数据比基于网格的方法更有效,但更难以实现。将端点和线分组为重叠网格可能是2&的良好优化。 3。

请注意,我认为在您的问题中使用“最近邻居”一词具有误导性,因为这与“一条线的给定距离内的所有点”或“另一点的给定半径内的所有点”不同”。最近邻居通常意味着单个结果,并不等于“在给定的点到点或点到线距离内”。