优化在 Z^3 中查找邻居

optimizing finding neighbors in Z^3

本文关键字:查找 邻居 优化      更新时间:2023-10-16

我在 Z^3(整数 3 元组(中有一个点数组。

如何快速确定每个点的邻居?其中相邻点是距离正好一个单位距离的点(欧几里得度量(。

例如,假设数组为:

{ {0,0,0}, {0,0,1}, {1,1,1} }

那么{0,0,0}{0,0,1}是邻居,{1,1,1}没有邻居。

目前,我正在按字典顺序对std::vector中的所有点进行排序,然后使用std::lower_bound搜索邻居(6 个二叉搜索(。这比对我的测试数据使用std::unordered_map要快得多。

有没有另一种方法可以更快?(请注意,我不能使用常规网格,因为点可能相距很远。另请注意:由于下面有一些混淆,这是一个关于优化的问题,而不是正确性。我上面建议的实现是微不足道的。

对于测试数据集,假设有一个半径为 256 的体素化球体。

请注意,我不能使用常规网格,因为点可能很远 分开

体育场中的茶壶问题可以通过多级网格或一些八叉树来解决。每个节点包含其父节点的 1/8 卷。由于一切都是整数,因此您可以通过字符而不是整数来执行此操作。他们只需要在树上上走一次,检查邻居的孩子,如果空了,上去两次,检查邻居的父母。这应该比检查整个阵列(多少个?(快得多(最近邻居可能只有 64 个节点(。我想只有 64 个节点就足够了,因为通过为每个点只检查 x0+1,y0+1,z0+1,你不需要检查 x0-1、y0-1、z0-1,因为它重复了相同的东西。因此,包括自身和邻居(所有父节点(是 8x8=64 个最近的邻居节点(即使是对角线,您当然可以省略它们(也许您可以省略对角线并仅检查 3x8=24 个节点。

当节点中没有点时,不要构建该节点。如果有,则只需有一个字符值 0,1,2,3,4,5,6,7,从其父级的角度显示其 (z 索引(。

还可以为静止点提供缓存,这可能是为了在需要重新计算场景时减少计算次数。

这是一个 O(N*log(N(( 解决方案:

  1. 按字典顺序对向量进行排序。
  2. 遍历向量以查找哪些项与向量中的前置项正好相距一个单位。 即

    bool pointsAreNeighbors = (abs(item[0]-prevItem[0])+abs(item[1]-prevItem[1])+abs(item[2]-prevItem[2])==1);

    如果上述表达式计算为 true,请将item(及其前身prevItem(作为键/值对插入到std::map(或类似的基于键/值的数据结构(中,因为它们是结果集的一部分。

  3. 再次按字典顺序对向量进行排序,但这次使用自定义排序函子,以便将每个项目中的中间值视为最低阶子排序条件(而不是最后一个值(。

  4. 重复步骤 2,
  5. 再次按字典顺序对向量进行排序,但这次使用自定义排序函子,以便将每个项目中的第一个值视为最低阶子排序条件(而不是最后一个值或中间值(。
  6. 重复步骤 2。
  7. 此时,结果集应包含所有相邻对。

注意:最终的结果集可能包含一些冗余对(例如,它可能同时包含(A,B(和(B,A(((——根据您的用例,您可能希望也可能不希望在之后过滤掉这些对,或者向步骤(2(添加一些额外的逻辑,以便在将任何"乱序对"插入结果集之前交换其键和值。