3D 阵列(1D 平面)索引

Posted

技术标签:

【中文标题】3D 阵列(1D 平面)索引【英文标题】:3D array (1D flat) indexing 【发布时间】:2013-12-14 11:53:53 【问题描述】:

我正在使用坐标系 x(宽度)、y(高度)、z(深度)

只是为了消除混淆,如果有任何 x 和 y 是平面,我使用 Z 作为高程。

我将每秒访问数组数百万次,基准测试表明使用索引的一维数组更快,我希望尽可能提高效率,以便其他事物可以使用该时间

例如一个二维数组 --> 一维数组的创建只是

Object[] oneDArray = new Object[width * height]

要索引数组,我可以使用以下内容。

Object obj = oneDArray[x + y * width]

我确实在 *** 上找到了以下内容,但我不完全确定哪一个是正确的 How to "flatten" or "index" 3D-array in 1D array?

“正确”的答案说要索引数组,请执行以下操作

Object[] oneDArray = new Object[width * height * depth]
Object obj = oneDArray[x + WIDTH * (y + DEPTH * z)]

但是另一个答案说“正确”的答案是错误的并使用以下

Object[] oneDArray = new Object[width * height * depth]
Object obj = oneDArray[x + HEIGHT* (y + WIDTH* z)]

读取扁平 3D 数组的正确方法是什么?

【问题讨论】:

对于您当前对宽度、高度和深度的定义,这两种变体都不正确。 您的分析是否表明这将是主要瓶颈?因为否则你会因为一点点收获而让自己头疼 【参考方案1】:

这里有一个 Java 解决方案,可以同时满足您的要求:

从 3D 到 1D 从 1D 到 3D

我自己的微基准测试表明,一维数组获取/设置值的速度比通过 3D 数组快 50%。

下面是我选择遍历 3D 矩阵的路径的图解说明,单元格按遍历顺序编号:

转换函数:

public int to1D( int x, int y, int z ) 
    return (z * xMax * yMax) + (y * xMax) + x;


public int[] to3D( int idx ) 
    final int z = idx / (xMax * yMax);
    idx -= (z * xMax * yMax);
    final int y = idx / xMax;
    final int x = idx % xMax;
    return new int[] x, y, z ;

上面的代码当然可以分解为更快,但我保留它是为了更容易理解 2 路转换;)

【讨论】:

【参考方案2】:

使用公式index = x*height*depth + y*depth + z 示例 java 代码说明。

public class FlattenedArray 
    public static void main(String[] args) 
        int width = 2;
        int height = 3;
        int depth = 4;
        int[][][] d3 = new int[width][height][depth];
        int[] d1 = new int[width*height*depth];

        //3D Array :
        int w=0;
        for(int i=0;i<width;i++) 
            for(int j=0;j<height;j++)
                for(int k=0;k<depth;k++) 
                    d3[i][j][k] = ++w;
                    System.out.print(d3[i][j][k] + " ");
                
        System.out.println();

        //1D Array :
        w=0;
        for(int i=0;i<width;i++) 
            for(int j=0;j<height;j++)
                for(int k=0;k<depth;k++) 
                    int index = i*height*depth + j*depth + k;
                    d1[index] = ++w;
                

        for(int i=0;i<width*height*depth;i++) 
            System.out.print(d1[i] + " ");
        
    

【讨论】:

【参考方案3】:

这取决于您希望如何在一维数组中对 3D 数据进行排序, 如果您想按顺序排列索引:Z、Y、X,那么您的 2x2x2 尺寸 3D 数据将像这样存储:

index 0: [z=0,y=0,x=0]
index 1: [z=0,y=0,x=1]
index 2: [z=0,y=1,x=0]
index 3: [z=0,y=1,x=1]
index 4: [z=1,y=0,x=0]
index 5: [z=1,y=0,x=1]
index 6: [z=1,y=1,x=0]
index 7: [z=1,y=1,x=1]

DEPTH 维度对应z,HEIGHT 对应y,WIDTH 对应x

索引计算将是:index = HEIGHT*WIDTH*z + WIDTH*y + x

x 不乘以任何东西,因为下一个 x 索引就在前一个索引之后。

如果您想跳过 Y 行,则必须添加整行 WIDTH,在本例中为 2,例如,如果您位于索引 1,它的 z=0,y=0 和 x=1 并且您添加WIDTH=2 来索引,你会得到索引 3。只有 y 维度增加了 1。

要从 z=0 移动到 z=1,您必须跳过 4 个索引(查看索引列表),数字是 HEIGHT*WIDTH(在本例中为 2*2)。

性能

为了提高速度,最好处理您的 3D 数据,其中 z、y、x 坐标按顺序递增,这样您就不必经常重新计算索引。例如:

int z = 1, y=1, x=0;
int index = HEIGHT*WIDTH*z + WIDTH*y;
int data;

for(x=0;x<WIDTH;x++)

    Object obj = oneDArray[index+x];

在理想情况下,所有数据处理都是相互独立的,您甚至不必计算索引,只需在整个oneDArray 中增加一个索引即可。可以预先计算的内容取决于您的使用情况。

【讨论】:

以上是关于3D 阵列(1D 平面)索引的主要内容,如果未能解决你的问题,请参考以下文章

如何在一维数组中“扁平化”或“索引” 3D数组?

将1D阵列添加到现有2D阵列

matplotlib - 来自矩形高度阵列的 3d 表面

使用树来加速具有周期性边界条件的 3D 阵列上的最近邻搜索

当期望1d阵列时,传递列向量y

光线投射和二维阵列在 Unity 中的魔方无法按预期工作