在模拟粒子相互作用时,我偶然发现了莫顿顺序(Z 顺序)(维基百科链接)的网格索引,它被认为可以提供有效的最近邻单元搜索。我读过的主要原因是内存中空间接近的单元的几乎顺序排序。
在第一次实现的过程中,我无法思考如何有效地实现最近邻居的算法,尤其是与基本的统一网格相比。
给定一个单元格 (x,y),获取 8 个相邻单元格索引并计算相应的 z 索引是很简单的。尽管这提供了对元素的恒定访问时间,但必须计算或在预定义的表中查找 z-index(每个轴和 OR'ing 分开)。这怎么可能更有效率?是否真的,按 A[0] -> A 1 -> A[3] -> A[4] -> ...的顺序访问数组 A 中的元素比按 A[1023 的顺序访问更有效] -> A[12] -> A[456] -> A[56] -> ...?
我期望存在一种更简单的算法来以 z 顺序查找最近的邻居。类似的东西:找到邻居的第一个单元格,迭代。但这不可能是真的,因为这只能在 2^4 大小的块内很好地工作。但是有两个问题:当单元格不在边界上时,可以很容易地确定块的第一个单元格并遍历块中的单元格,但必须检查该单元格是否是最近邻。更糟糕的是,当单元格位于边界上时,必须考虑 2^5 个单元格。我在这里想念什么?是否有一种相对简单有效的算法可以满足我的需求?
第 1 点中的问题很容易测试,但我对所描述的访问模式生成的底层指令不是很熟悉,并且真的很想了解幕后发生的事情。
在此先感谢您的任何帮助、参考等...
编辑:
感谢您澄清第 1 点!因此,通过 Z 排序,相邻单元的缓存命中率平均增加,这很有趣。有没有办法分析缓存命中/未命中率?
关于第 2 点:我应该补充一点,我了解如何为 R^d 中的点云构建莫顿有序数组,其中索引 i = f(x1, x2, ..., xd) 是从逐位隔行扫描等获得的。我试图理解的是是否有比以下天真 ansatz 更好的方法来获取最近的邻居(这里在 d=2 中,“伪代码”):
// Get the z-indices of cells adjacent to the cell containing (x, y)
// Accessing the contents of the cells is irrelevant here
(x, y) \elem R^2
point = (x, y)
zindex = f(x, y)
(zx, zy) = f^(-1)(zindex) // grid coordinates
nc = [(zx - 1, zy - 1), (zx - 1, zy), (zx - 1, zy + 1), // neighbor grid
(zx , zy - 1), (zx, zy + 1), // coordinates
(zx + 1, zy - 1), (zx + 1, zy), (zx + 1, zy + 1)]
ni= [f(x[0], x[1]) for x in nc] // neighbor indices