【问题标题】:Finding particles in the same cell on a 2d grid在二维网格上的同一单元格中查找粒子
【发布时间】:2017-02-23 20:24:52
【问题描述】:

这是一种算法问题,与任何特定语言无关。

假设我有Np 点粒子在二维平面上具有连续(读取doublex, y 坐标。二维平面被划分为N ⨉ N 个单元。

对于每个粒子,我想要一种快速的方法(比O(Np^2) 更快)在同一个单元格中找到其他粒子。 另外,我不想在内存使用上走得太远,所以我不想再存储一个N ⨉ N + Np 数组。

我“发明”了一种棘手的方法来实现这一点,但我提出这个问题是为了以防万一有一种规范的方法可以做到这一点。

【问题讨论】:

  • 为每个粒子添加一个字段,说明它在哪个单元格中?
  • 也许他正在寻找 Voronoi 图...
  • @SirGuy,但是你需要解析所有粒子Np^2次。
  • 能够廉价地更新所使用的数据结构很重要,例如,在粒子移动了变化的单元格之后?还是只是应该优化的查询?
  • @BitTickler,你能解释一下在这种情况下如何利用 Voronoi 图吗?

标签: arrays algorithm particles


【解决方案1】:

执行此操作的规范方法是使用空间索引数据结构,例如a kd-treeO(Np*log(Np)) 构建时间,O(Np^(1−1/K)+Mp) 轴对齐范围(这是您的单元格)查询时间(K=2 个维度,Mp 个报告点),O(Np) 个空间。

【讨论】:

    【解决方案2】:

    这是一个 O(Np * log(Np)) 时间和 O(Np) 内存的解决方案:

    Initialize a dynamic DS container with {row,col} tuple as a key \
        and a list of particles as a value
    Iterate over each particle
        Find {row, col} tuple for current particle
        Find a value-list in container by {row, col} key
        If there is no value in container for a value by this key
            Then initialise a new particle list
        Append current particle to a value-list
    

    容器可以实现为平衡二叉树,这将使 log(Np) 乘以整体时间复杂度。


    用 O(Np + N) 时间和 O(N) 内存解决方案的另一种方法:

    Initialize a simple lookup array byRow of size N, \
        it will contain a list of particles in each cell
    Iterate over each particle
        Place the particle in corresponding cell of lookup array byRow by its ROW
    Initialize another lookup array byCol of size N, \
        it will contain a list of particles in each cell as well
    Iterate over each cell of lookup list byRow 
        Iterate over each particle of the list in byRow[cellRow]
            Place the particle in corresponding cell of byCol by its COL
        Iterate over each particle of the list in byRow[cellRow]
            \\ Now you have a list of other particles in the same NxN cell
            \\ by looking at byCol[particleCol]
            If byCol[particleCol] is not cleared
                Print byCol[particleCol] list or put into other global storage and use later \
            Clear byCol[particleCol] list
    

    这个想法很简单。首先,您按行对粒子进行分组,将它们存储在byRow 数组的列表中。然后对于byRow 数组的每个列表的粒子,您按列进行相同的分组。每次重用 byCol 数组时。所以整体内存复杂度是O(N)。即使我们有两个相互嵌套的循环,我们仍然有 O(Np + N) 时间复杂度,因为内部步骤不会执行超过 Np 次。

    编辑:准确地说,时间复杂度为 O(Np + N)。

    【讨论】:

    • 但是你需要N⨉N+Np 内存来将粒子存储在那个容器中,对吧?如果您有数百万个粒子飞来飞去,那将是一个糟糕的选择。
    • @Hayk Hakobyan,不,你没有。算法的第一步不会为每个可能的 {row,col} 元组创建一个粒子列表。此列表在主体循环中创建。只有在实际需要时才创建值列表。最多你会有 Np 个这样的列表(每个有一个粒子),以防所有 {row, col} 对于所有粒子都是不同的。
    • 好的,我想我明白了。我有一个类似的想法,但我想给每个粒子一个索引(根据它们的单元格正确排序)并存储给定单元格中的粒子总数,而不是键值列表。这是内存中的N^2 和时间中的Np (Np log(Np)?)。
    • @Hayk Hakobyan,如果您将使用N^2 内存,您可以在O(Np) 时间执行。所以我的解决方案只使用了O(Np) 内存,但工作速度慢了log(Np) 倍。
    • 该算法需要 O(Np + N^2) 时间,因为您必须为 byRow 中的每个条目迭代 byCol。不过,这很好,只要您选择 N 为 O(sqrt(Np))。
    【解决方案3】:

    构造一个由(使用的单元格 id,该单元格中的粒子列表)按单元格 id 排序的已排序元组的列表(或数组)。单元格 id 可能只是它的 (x, y) 坐标。空间复杂度为O(Np)。构建它应该花费O(Np log(Np)) 时间。然后通过标准二分搜索在同一个单元格中查找粒子O(log(Np))

    要在这些复杂性估计中将log(Np) 替换为1 以获得O(Np) 构造时间和O(1) 查找,请将排序列表替换为哈希表。

    【讨论】:

      【解决方案4】:

      除了将粒子列表附加到每个单元格之外,没有真正的答案。这是另一个 N x N + p 数据结构。不过内存很便宜,应该买得起。

      【讨论】:

      • 好吧,除非你有数以百万计的粒子飞来飞去:)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-08-20
      相关资源
      最近更新 更多