使用数组实现 Matrix 构造时,哪个更有效?使用一维数组还是数组数组(二维)?
我认为 2D 更有效,因为您已经拥有元素的 X 和 Y 坐标,而在 1D 实现中,您必须计算索引。
编辑:它正在使用 Java 实现
使用数组实现 Matrix 构造时,哪个更有效?使用一维数组还是数组数组(二维)?
我认为 2D 更有效,因为您已经拥有元素的 X 和 Y 坐标,而在 1D 实现中,您必须计算索引。
编辑:它正在使用 Java 实现
“高效”并不是一个包罗万象的术语。
数组的数组解决方案在存储方面更有效,其中数组可能是稀疏的(即,您可以使用空指针来表示全为零的矩阵行)。这将是(在 C 中):
int *x[9];
每个"int *"
都将单独分配。
二维数组(不一定是数组数组)通常会更快(在速度方面效率更高),因为它可以通过数学计算内存位置,而无需取消引用内存位置。我说的是构造:
int x[9][9];
一维数组的形式:
int x[81];
不太可能比等效的 2D 版本更快,因为您仍然需要在某些时候进行计算才能找到正确的单元格(在您的代码中手动而不是让编译器来做)。
编辑后添加 Java 作为要求:
我相信 Java 2D 数组属于数组类型的数组(这将需要两次内存访问,而不是 1D 数组所需的一次),因此具有手动索引计算的 1D 数组可能会更快。所以,而不是声明和使用:
int x[width][height];
x[a][b] = 2;
您可以通过以下方式获得更快的速度:
int x[width*height];
x[a*height+b] = 2;
您只需要注意不要在任何地方混淆公式(即不要无意中交换 4 和 7)。
这种速度差异基于我认为 Java 在幕后编码的方式,所以我可能是错的(但我对此表示怀疑 :-)。我的建议是,一如既往地优化问题,衡量,不要猜测!
我将用迄今为止的答案打破排名,并提出以下原因,即一维数组很可能更快。
二维数组涉及 2 次内存访问。例如,A[x][y] 首先必须查找 A[x],然后再查找该数组 [y]。
一维实现传统上是 A[x + (width *y)]。当宽度在寄存器(或文字)中时,这意味着 2 个数学运算和 1 个查找而不是 2 个查找。查找比数学运算慢几个数量级,所以如果宽度在寄存器中的比例很小,或者是文字,它会更快。
当然,标准警告适用。始终分析并避免过早的优化。
如果不实际编写示例代码并测试结果,我认为无法回答这个问题。例如这个问题发现了以下结果。
sum(double[], int): 2738 ms (100%)
sum(double[,]): 5019 ms (183%)
sum(double[][]): 2540 ms ( 93%)
锯齿状数组最快,其次是一维数组,其次是多维数组。锯齿状阵列最快可能不是人们所预料的。这些结果可能对 Java 毫无用处,因为 Java 有不同的优化(Java 中没有多维数组)。
我会非常小心地做出假设。 例如,如果您在 2D 数组的一行上循环,Java 可能会优化索引查找或越界检查,如果您使用具有内联索引计算的 1D 数组,Java 可能无法做到这一点。
我建议编写一个简单的程序来测试所需平台上的速度。
根据语言的不同,不会有任何区别。真正的问题是如何分配二维矩阵。它是 X*Y 字节的单个连续空间,还是分配为 X 大小的 Y 独立数组。后者通常在创建稀疏矩阵时完成。
我在作为机械工程师的职业生涯中使用的商业有限元包,它使用一维数组作为其线性代数计算的基础。有限元方法导致矩阵大、稀疏和带状。将所有这些零元素存储在带外是没有意义的。
唯一一次您会看到二维数组用于小型学术问题或不稀疏的问题(例如,边界元素方法)。
在一般情况下,任何算法的最有效实现是具有最少代码量的算法。这有很多原因:
它还很大程度上取决于访问模式。你总是走整个矩阵吗?稀疏吗?您喜欢处理行还是列?
在极端情况下(具有 10 亿行和列的矩阵,仅使用 10 个单元格),aHashMap
可以比任何数组实现更有效。对于其他问题,根据问题混合方法可能更有效(例如,HashMap
当单元格“聚集”在巨大的空白空间中时,一组迷你矩阵)。
如果您的问题要求定位行/列然后处理这些值,则使用 2D 方法可能更有效,因此第一次访问会返回一个数组,然后您可以处理该数组而无需担心边界、一次性错误、等等