使用arrays数组(2D)或一维数组实现更高效的矩阵?

使用数组实现Matrix构造时哪个更有效? 使用一维数组或数组数组(2D)?

我认为2D更有效,因为您已经拥有元素的X和Y坐标,在1D实现中您必须计算索引。

编辑:它正在使用Java实现

“高效”并不是一个包罗万象的术语。

arraysarrays解决方案在存储方面更有效,其中arrays可能是稀疏的(即,您可以使用空指针来表示所有零的矩阵线)。 这将是(在C中):

int *x[9]; 

其中每个"int *"将分别分配。

2D数组(不一定是数组的数组)通常会更快(在速度方面有效),因为它使用数学计算出存储器位置,而不必去除存储器位置。 我在谈论这个结构:

 int x[9][9]; 

forms的一维数组:

 int x[81]; 

因为你仍然需要在某些时候进行计算以找到正确的单元格(在代码中手动而不是让编译器这样做),因此不太可能比同等的2D版本更快。

在编辑之后添加Java作为要求:

我相信Java 2D数组具有多种数组(这将需要两次内存访问,而不是一维数组所需的内存访问),因此具有手动索引计算的一维数组可能更快。 所以,而不是声明和使用:

 int x[width][height]; x[a][b] = 2; 

你可以获得更快的速度:

 int x[width*height]; x[a*height+b] = 2; 

你只需要小心,不要让公式在任何地方混淆(即不要无意中交换4和7)。

这种速度差异是基于我认为Java被编码的方式,所以我可能是错的(但我怀疑它:-)。 我的建议是,一如既往的优化问题, 衡量,不要猜!

我打算用日期答案打破排名并提出以下原因:一维数组可能更快。

2Darrays涉及2次存储器访问。 例如,[x] [y]首先必须查找A [x],然后对该数组[y]进行另一次查找。

传统上,1D实现将是A [x +(宽度* y)]。 当宽度在寄存器(或文字)中时,这意味着2个数学运算和1个查找而不是2个查找。 查找比数学运算慢几个数量级,因此如果宽度在寄存器中即使是一小部分时间,或者是文字,它也会更快。

当然标准警告适用。 始终进行概要分析,避免过早优化。

我不认为在没有实际编写示例代码和测试结果的情况下可以回答这个问题。 例如, 这个问题找到了以下结果。

 sum(double[], int): 2738 ms (100%) sum(double[,]): 5019 ms (183%) sum(double[][]): 2540 ms ( 93%) 

锯齿状数组最快,其次是1维数组,其次是多维数组。 锯齿状arrays最快可能不是人们所预测的。 这些结果可能对Java无用,因为Java有不同的优化(并且Java中没有多维数组)。

我会非常小心地做出假设。 例如,如果您循环遍历2D数组的一行,Java可能会优化索引查找或超出范围检查,如果您使用具有内联索引计算的一维数组,它可能无法检查。

我建议编写一个简单的程序来测试所需平台的速度。

根据语言的不同,没有区别。 真正的问题是如何分配2D矩阵。 它是X * Y字节的单个连续空间,还是分配为X大小的Y独立数组。 后者通常在创建稀疏矩阵时完成。

我在职业生涯中用作机械工程师的商业有限元软件包,使用一维数组作为线性代数计算的基础。 有限元方法导致大,稀疏和带状的基质。 将所有零元素存储在乐队之外是没有意义的。

您将看到2Darrays使用的唯一时间是针对小型学术问题或非稀疏的问题(例如,边界元素方法)。

在一般情况下,任何算法的最有效实现是具有最少量代码的算法。 这有很多原因:

  • 更少的代码 – >更少的时间来编写它
  • 更少的代码行意味着更少的错误(因为每个KLOC的错误对于给定的程序员来说非常稳定),这些错误更容易找到(因为它们无法在几行代码中隐藏得很好)
  • 如果您的算法不适合该任务,则在10行而不是100行时更容易替换
  • 紧凑的实现通常会导致干净的界面,这使得使用库的代码清理(因此效果倍增)。 如果这使得客户端代码更有效(即您将工作集中在一个地方以使其他一切变得更简单),这也可以导致更复杂的库实现。

它还取决于访问模式。 你总是走遍整个矩阵吗? 它稀疏吗? 您更喜欢处理行还是列?

在极端情况下(矩阵有十亿行和一列只使用了10个单元格), HashMap可以比任何数组实现更高效。 对于其他问题,根据问题混合方法可能更有效(例如,当细胞在巨大的空白空间中“聚集”时,迷你矩阵arrays的HashMap )。

如果您的问题要求定位行/列然后处理这些值,那么使用2D方法可能更有效,因此第一次访问返回一个数组,然后您可以处理该数组而不必担心边界,一次性错误,等等