将一个大矩阵表示为一维阵列比二维阵列更有效吗?

时间:2016-04-05 13:54:00

标签: java arrays memory heap-memory seam-carving

上下文

我正在实施seam carving算法。

我将图片中的像素表示为1D数组

private int[] picture;

每个int代表像素的RGB。

要访问像素,我使用辅助方法,例如:

private int pixelToIndex(int x, int y) {return (y * width()) + x;}

替代方案是存储在2D数组中:

private int[][] picture;

接缝雕刻算法分为两部分。

首先,它进行一些图像处理,它找到具有最低能量的水平或垂直连接接缝。这里像素访问跨越行跳过一点。

其次,它会移除此连接的接缝。

对于垂直接缝,我使用-1标记要移除的像素,并创建一个新的图片数组,跳过删除的像素,如下所示:

int i = 0, j = 0;
while (i < temp.length) {
    if (picture[j] != -1) {
        temp[i++] = picture[j];
    }
    j++;
}
picture = temp;

对于水平接缝,在给定特定列的情况下,我将该列的删除像素之后的所有像素向上移动一行,如下所示:

for (int i = 0; i < temp.length; i++) {
    int row = indexToY(i);
    int col = indexToX(i);
    int deletedCell = seam[col];

    if (row >= deletedCell) temp[i] = picture[i + width()];
    else temp[i] = picture[i];
}
picture = temp;

问题

显然,由于每个子阵列的开销,1D阵列使用较少的物理内存,但考虑到迭代矩阵的方式,CPU会更有效地缓存2D阵列,从而提高效率吗?

如何将数组加载到CPU缓存和RAM中的方式有​​所不同?部分1D阵列会进入L1缓存吗?如何将1D和2D阵列加载到内存中?它会依赖于数组的大小吗?

2 个答案:

答案 0 :(得分:1)

一个int数组就是这样表示的:一个int值数组。数组数组......增加了一定的开销。所以,简短回答:处理真正大量数据量时;普通的一维数组是你的朋友。

另一方面:只有在了解瓶颈后才开始优化。您知道,当您的应用程序花费大部分时间等待IO时,优化内存数据结构并没有太大帮助。如果您尝试编写“高性能”代码会产生“复杂,难以阅读,难以维护”的代码......您可能会专注于错误的区域。

此外:具体的性能数字受到许多不同变量的影响。所以你想先做分析;并了解不同硬件,不同数据集等会发生什么。

另一方面注意:有时候,对于真正的数字嘎吱嘎吱;它也可以是一个可行的选择,用C ++实现的东西可以通过JNI进行调用。这真的取决于你的问题的性质;事情的使用频率;用户期望的响应时间;等等。

答案 1 :(得分:1)

Java具有用于多维数组的数组数组。在您的情况下,int[][]int[]的数组(当然int[]是一个int数组)。因此,矩阵表示为每行的一组行和指针。在这种情况下,它意味着NxM矩阵占用数据和指针数组的NxM。

由于您可以将任何矩阵表示为数组,因此可以减少以这种方式存储的内存消耗。

另一方面,在将2D矩阵表示为文件的情况下,地址操作并不复杂。

如果我们假设你有一个NxM访问的矩阵和一个大小为NxM的数组代表这个矩阵,你可以访问Matrix[x,y]的元素Array[x*n+y]

Array[i]是紧凑的,它很可能在L1缓存中,甚至在寄存器缓存中。

Matrix[x,y]需要一个内存读取和添加 Array[x*n+y]需要一次乘法和一次加法。

所以,我将把我的两分钱放在Array上,但无论如何它必须是tested(别忘了等待JIT编译器的加热时间)