我在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的体素化球体。
答案 0 :(得分:1)
请注意,我不能使用常规网格,因为这些点可能很远 分开
体育场中的茶壶问题可以通过多层网格或某些八叉树来解决。每个节点包含其父节点的1/8体积。由于所有内容都是整数,因此您可以用char代替整数来完成此操作。他们只需要在树上向上走一次,并检查邻居的孩子,如果空了,就上两次,检查邻居的父母。这应该比检查整个数组(多少?)要快得多(对于最近的邻居可能只有64个节点)。我猜只有64个节点就足够了,因为通过仅检查每个点的x0 + 1,y0 + 1,z0 + 1,您不需要检查x0-1,y0-1,z0-1,因为它重复了相同的事情。因此,包括自身和邻居(所有父母),最接近的邻居是8x8 = 64个节点(即使是对角线,您也可以省略它们),也许您可以省略对角线并仅检查3x8 = 24个节点。
当节点中没有点时,请勿构建该节点。如果存在,则只需具有一个char值0、1、2、3、4、5、6、7,即可从其父级的角度显示其(z索引)。
还可以为固定点提供缓存,这可能在需要重新计算场景时减少了计算量。
答案 1 :(得分:0)
这是一个O(N * log(N))解决方案:
遍历向量,以查找哪些项目与其向量中的前任恰好相距一个单位。即
bool pointsAreNeighbors = (abs(item[0]-prevItem[0])+abs(item[1]-prevItem[1])+abs(item[2]-prevItem[2])==1);
如果以上表达式计算为真,则将item
(及其前身prevItem
)作为键/值对插入std::map
(或类似的基于键/值的数据)中结构),因为它们是结果集的一部分。
再次按字典顺序对向量进行排序,但这次使用自定义排序功能将每个项目中的中间值视为最低顺序的子排序标准(而不是最后一个值)。 / p>
注意:最终结果集可能包含一些冗余对(例如,可能同时包含(A,B)和(B,A))-根据您的用例,您可能会或可能不希望过滤这些对之后,或者在步骤(2)中添加一些额外的逻辑,以交换任何“乱序”的键和值,然后再将其插入结果集中。