在c#中,多维数组double[,]和数组的数组double[][]有什么区别?
如果有区别,每一种的最佳用途是什么?
在c#中,多维数组double[,]和数组的数组double[][]有什么区别?
如果有区别,每一种的最佳用途是什么?
当前回答
交错数组是数组的数组,或者每一行包含一个自己的数组的数组。
这些数组的长度可以不同于其他行的长度。
声明和分配数组的数组
与常规多维数组相比,锯齿数组声明的唯一不同之处在于,我们不只有一对括号。对于锯齿状数组,每个维度都有一对括号。我们这样分配它们:
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存储在程序的执行堆栈中,并指向动态内存中的一个块,该块包含对内存中其他三个块的三个引用序列;它们每个都包含一个整数数组——锯齿数组的元素:
其他回答
简单地说,多维数组类似于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
除了其他答案之外,请注意,多维数组被分配为堆上的一个大块对象。这有一些含义:
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.
数组的数组(锯齿数组)比多维数组更快,可以更有效地使用。多维数组有更好的语法。
如果你使用交错数组和多维数组写一些简单的代码,然后用IL反汇编器检查编译后的程序集,你会发现从交错数组(或一维数组)中存储和检索是简单的IL指令,而多维数组的相同操作是方法调用,总是比较慢。
考虑以下方法:
static void SetElementAt(int[][] array, int i, int j, int value)
{
array[i][j] = value;
}
static void SetElementAt(int[,] array, int i, int j, int value)
{
array[i, j] = value;
}
他们的IL将如下:
.method private hidebysig static void SetElementAt(int32[][] 'array',
int32 i,
int32 j,
int32 'value') cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: ldelem.ref
IL_0003: ldarg.2
IL_0004: ldarg.3
IL_0005: stelem.i4
IL_0006: ret
} // end of method Program::SetElementAt
.method private hidebysig static void SetElementAt(int32[0...,0...] 'array',
int32 i,
int32 j,
int32 'value') cil managed
{
// Code size 10 (0xa)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: ldarg.2
IL_0003: ldarg.3
IL_0004: call instance void int32[0...,0...]::Set(int32,
int32,
int32)
IL_0009: ret
} // end of method Program::SetElementAt
当使用锯齿状数组时,可以轻松地执行行交换和行大小调整等操作。也许在某些情况下使用多维数组会更安全,但即使Microsoft FxCop也告诉我们,当您使用锯齿数组来分析您的项目时,应该使用锯齿数组而不是多维数组。
交错数组是数组的数组,或者每一行包含一个自己的数组的数组。
这些数组的长度可以不同于其他行的长度。
声明和分配数组的数组
与常规多维数组相比,锯齿数组声明的唯一不同之处在于,我们不只有一对括号。对于锯齿状数组,每个维度都有一对括号。我们这样分配它们:
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存储在程序的执行堆栈中,并指向动态内存中的一个块,该块包含对内存中其他三个块的三个引用序列;它们每个都包含一个整数数组——锯齿数组的元素:
这可能在上面的回答中提到过,但没有明确地提到:对于锯齿数组,您可以使用array[row]引用整行数据,但这对于多维数组是不允许的。