很多时候,您希望数组的性能优于链表,但又不符合矩形数组的要求。
作为一个例子,考虑一个六边形网格,这里用中灰色显示单元格 (3, 3) 的 1 距离邻居和浅灰色的 2 距离邻居。
假设我们想要一个数组,其中包含每个单元格的每个 1 距离和 2 距离邻居的索引。一个小问题是单元格具有不同数量的 X 距离邻居 - 网格边界上的单元格比靠近网格中心的单元格具有更少的邻居。
(出于性能原因,我们想要一个相邻索引数组——而不是从单元坐标到相邻索引的函数。)
我们可以通过跟踪每个单元格有多少邻居来解决这个问题。neighbors2
假设您有一个size数组
R x C x N x 2
,其中R
是网格行数,C
对于列,并且N
是网格中任何单元格的最大 2 距离邻居数。然后,通过保留一个额外n_neighbors2
的 size数组R x C
,我们可以跟踪填充了哪些索引,neighbors2
哪些只是零填充。例如,要检索单元格 (2, 5) 的 2 距离邻居,我们只需像这样对数组进行索引:
someNeigh = neighbors2[2, 5, 0..n_neighbors2[2, 5], ..]
someNeigh
将是一个n_neighbors2[2, 5] x 2
索引数组(或视图),其中someNeigh[0, 0]
产生第一个邻居的行,并someNeigh[0, 1]
产生第一个邻居的列,依此类推。注意位置的元素
neighbors2[2, 5, n_neighbors2[2, 5]+1.., ..]
无关紧要;这个空间只是填充以保持矩阵矩形。
假设我们有一个函数可以找到任何单元格的 d 距离邻居:
import Data.Bits (shift)
rows, cols = (7, 7)
type Cell = (Int, Int)
generateNeighs :: Int -> Cell -> [Cell]
generateNeighs d cell1 = [ (row2, col2)
| row2 <- [0..rows-1]
, col2 <- [0..cols-1]
, hexDistance cell1 (row2, col2) == d]
hexDistance :: Cell -> Cell -> Int
hexDistance (r1, c1) (r2, c2) = shift (abs rd + abs (rd + cd) + abs cd) (-1)
where
rd = r1 - r2
cd = c1 - c2
我们如何创建上述数组neighbors2
和n_neighbors2
?N
假设我们事先知道 2 距离邻居的最大数量 。然后可以修改generateNeighs
为始终返回相同大小的列表,因为我们可以用 (0, 0) 填充剩余的条目。在我看来,这留下了两个问题:
- 我们需要一个填充函数,
neighbors2
它不是对每个单独的索引进行操作,而是对一个切片进行操作,在我们的例子中,它应该一次填充一个单元格。 n_neighbors2
应同时填充为neighbors2
欢迎使用repa
or 或accelerate
数组的解决方案。