在c#中,多维数组double[,]和数组的数组double[][]有什么区别?

如果有区别,每一种的最佳用途是什么?


当前回答

简单地说,多维数组类似于DBMS中的表。 Array of Array(锯齿状数组)允许每个元素保存另一个相同类型的可变长度数组。

因此,如果您确定数据结构看起来像一个表(固定的行/列),您可以使用多维数组。锯齿数组是固定的元素&每个元素可以容纳一个可变长度的数组

例如Psuedocode:

int[,] data = new int[2,2];
data[0,0] = 1;
data[0,1] = 2;
data[1,0] = 3;
data[1,1] = 4;

我们可以把上面的表格看成一个2x2的表格:

1 | 2 3 | 4

int[][] jagged = new int[3][]; 
jagged[0] = new int[4] {  1,  2,  3,  4 }; 
jagged[1] = new int[2] { 11, 12 }; 
jagged[2] = new int[3] { 21, 22, 23 }; 

可以把上面的代码看成每一行都有可变的列数:

1 | 2 | 3 | 4 11 | 12 21 | | 22, 23

其他回答

前言:本评论旨在解决okutane提供的关于锯齿数组和多维数组之间性能差异的答案。

一种类型因为方法调用而比另一种类型慢的断言是不正确的。其中一种比另一种慢,因为它的边界检查算法更复杂。您可以通过查看编译后的程序集而不是IL轻松验证这一点。例如,在我的4.5安装中,访问存储在ecx指向的二维数组中的元素(通过edx中的指针),索引存储在eax和edx中,如下所示:

sub eax,[ecx+10]
cmp eax,[ecx+08]
jae oops //jump to throw out of bounds exception
sub edx,[ecx+14]
cmp edx,[ecx+0C]
jae oops //jump to throw out of bounds exception
imul eax,[ecx+0C]
add eax,edx
lea edx,[ecx+eax*4+18]

Here, you can see that there's no overhead from method calls. The bounds checking is just very convoluted thanks to the possibility of non-zero indexes, which is a functionality not on offer with jagged arrays. If we remove the sub, cmp, and jmps for the non-zero cases, the code pretty much resolves to (x*y_max+y)*sizeof(ptr)+sizeof(array_header). This calculation is about as fast (one multiply could be replaced by a shift, since that's the whole reason we choose bytes to be sized as powers of two bits) as anything else for random access to an element.

Another complication is that there are plenty of cases where a modern compiler will optimize away the nested bounds-checking for element access while iterating over a single-dimension array. The result is code that basically just advances an index pointer over the contiguous memory of the array. Naive iteration over multi-dimensional arrays generally involves an extra layer of nested logic, so a compiler is less likely to optimize the operation. So, even though the bounds-checking overhead of accessing a single element amortizes out to constant runtime with respect to array dimensions and sizes, a simple test-case to measure the difference may take many times longer to execute.

多维数组是(n-1)维矩阵。

所以int[,] square = new int[2,2]是一个方阵2x2, int[,] cube = new int[3,3,3]是一个立方-方阵3x3。比例不是必需的。

交错数组只是数组的数组——每个单元格包含一个数组的数组。

所以MDA是成比例的,JD可能不是!每个单元格可以包含任意长度的数组!

交错数组是数组的数组,或者每一行包含一个自己的数组的数组。

这些数组的长度可以不同于其他行的长度。

声明和分配数组的数组

与常规多维数组相比,锯齿数组声明的唯一不同之处在于,我们不只有一对括号。对于锯齿状数组,每个维度都有一对括号。我们这样分配它们:

int [] [] exampleJaggedArray; jaggedArray = new int[2][]; jaggedArray[0] = new int[5]; jaggedArray[1] = new int[3];

初始化数组的数组

int[][] exampleJaggedArray = { New int[] {5,7,2}, New int[] {10,20,40}, 新的int[] {3,25} };

内存分配

锯齿数组是引用的聚合。锯齿状数组不直接包含任何数组,而是有指向它们的元素。大小是未知的,这就是为什么CLR只保留对内部数组的引用。在我们为锯齿状数组的一个数组元素分配内存之后,引用开始指向动态内存中新创建的块。

变量exampleJaggedArray存储在程序的执行堆栈中,并指向动态内存中的一个块,该块包含对内存中其他三个块的三个引用序列;它们每个都包含一个整数数组——锯齿数组的元素:

除了其他答案之外,请注意,多维数组被分配为堆上的一个大块对象。这有一些含义:

Some multidimensional arrays will get allocated on the Large Object Heap (LOH) where their equivalent jagged array counterparts would otherwise not have. The GC will need to find a single contiguous free block of memory to allocate a multidimensional array, whereas a jagged array might be able to fill in gaps caused by heap fragmentation... this isn't usually an issue in .NET because of compaction, but the LOH doesn't get compacted by default (you have to ask for it, and you have to ask every time you want it). You'll want to look into <gcAllowVeryLargeObjects> for multidimensional arrays way before the issue will ever come up if you only ever use jagged arrays.

这可能在上面的回答中提到过,但没有明确地提到:对于锯齿数组,您可以使用array[row]引用整行数据,但这对于多维数组是不允许的。