【问题标题】:Finding shared vertices among polygons查找多边形之间的共享顶点
【发布时间】:2009-04-10 22:06:28
【问题描述】:

我很快就会遇到一个有趣的问题,我已经开始考虑算法。我想得越多,我就越害怕,因为我认为它会可怕地扩展 (O(n^4)),除非我能变得聪明。我很难对这个变得聪明。这是问题的简化描述。

我有 N 个多边形(其中 N 可以很大 >10,000,000),它们存储为 M 个顶点的列表(其中 M 大约为 100)。我需要为每个多边形创建一个在其他多边形之间共享的任何顶点的列表(将多边形视为周围感兴趣的区域,有时是这些区域但彼此相对)。我看到这样的东西

Polygon i | Vertex | Polygon j | Vertex
   1          1         2          2
   1          2         2          3
   1          5         3          1
   1          6         3          2
   1          7         3          3

这意味着多边形 1 中的顶点 1 与多边形 2 中的顶点 2 相同,多边形 1 中的顶点 2 与多边形 2 中的顶点 3 相同。同样,多边形 1 中的顶点 5 与顶点相同1 在多边形 3....

为简单起见,我们可以假设多边形从不重叠,它们最接近的是在边缘接触,并且所有顶点都是整数(以便于测试等式)。

我现在唯一能做的就是对于每个多边形,我必须遍历所有多边形和顶点,给我一个 O(N^2*M^2) 的缩放比例,这在我的情况。我可以有非常大的多边形文件,所以我什至不能将它们全部存储在 RAM 中,这意味着要多次读取文件。

这是我目前的伪代码

for i=1 to N
  Pi=Polygon(i)
  for j = i+1 to N
    Pj=Polygon(j)
    for ii=1 to Pi.VertexCount()
      Vi=Pi.Vertex(ii)
      for jj=1 to Pj.VertexCount()
        Vj=Pj.Vertex(jj)
        if (Vi==Vj) AddToList(i,ii,j,jj)
      end for
    end for
  end for
end for

我假设这已经出现在图形社区中(我没有花太多时间在那里,所以我不了解文献)。有任何想法吗?

【问题讨论】:

  • 忘了说 - 这只是 2D!

标签: geometry


【解决方案1】:

这是一个经典的迭代与内存问题。如果您将每个多边形与其他所有多边形进行比较,您将遇到 O(n^2) 解决方案。如果您在遍历所有多边形时构建一个表格,然后在表格中前进,您会得到一个很好的 O(2n) 解决方案。我在面试时问过类似的问题。

假设你有可用的内存,你想创建一个多重映射(一个键,多个条目),每个顶点作为键,多边形作为条目。然后,您可以将每个多边形恰好走一次,将顶点和多边形插入到地图中。如果顶点已经存在,则将多边形作为附加条目添加到该顶点键中。

一旦你击中了所有的多边形,你就可以遍历整个地图一次,然后对包含多个多边形条目的任何顶点做任何你需要做的事情。

【讨论】:

  • 现在,我只需要想办法有效地创建一个不适合内存的哈希表 :)
  • 查看 STL 容器。不要重新发明*,只需实现算法即可。 :)
【解决方案2】:

如果您有多边形/面数据,您甚至不需要查看顶点。

  • 从 [0..M] 创建一个数组(其中 M 是顶点数)
  • 遍历多边形并增加每个顶点索引的数组条目。

这为您提供了一个数组,该数组描述了每个顶点的使用次数。*

然后您可以再次遍历多边形并检查每个顶点的条目。如果它 > 1,则您知道该顶点由另一个多边形共享。

如果您需要存储/查找其他信息,您可以进一步构建此策略。例如,您可以将多边形直接存储在数组中,而不是计数,从而允许您获取使用给定顶点索引的所有面的列表。此时,您实际上是在创建一个以顶点索引为键的地图。

(*此示例假设您没有退化的多边形,但这些可以很容易地处理)。

【讨论】:

    【解决方案3】:

    嗯,一个简单的优化是制作一个映射(可​​能是哈希表),将每个不同的顶点(由其坐标标识)映射到它所属的所有多边形的列表。这会将您的运行时间减少到 O(NM) 之类的东西 - 仍然很大,但我怀疑您是否可以做得更好,因为我无法想象有任何方法可以避免检查所有顶点。

    【讨论】: