C#中的多维数组和数组数组之间有什么区别?
C#中的多维数组C#中的多维数组和数组数组之间有什么区别?,c#,multidimensional-array,jagged-arrays,C#,Multidimensional Array,Jagged Arrays,C#中的多维数组double[,]和数组数组数组double[]之间有什么区别 如果存在差异,那么每种阵列的最佳用途是什么?阵列阵列(锯齿阵列)比多维阵列更快,可以更有效地使用。多维数组有更好的语法 如果您使用交错数组和多维数组编写一些简单代码,然后使用IL反汇编程序检查编译后的程序集,您将看到交错数组(或一维数组)的存储和检索数组是简单的IL指令,而多维数组的相同操作是总是较慢的方法调用 考虑以下方法: static void SetElementAt(int[][] array, int i
double[,]
和数组数组数组double[]
之间有什么区别
如果存在差异,那么每种阵列的最佳用途是什么?阵列阵列(锯齿阵列)比多维阵列更快,可以更有效地使用。多维数组有更好的语法
如果您使用交错数组和多维数组编写一些简单代码,然后使用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也告诉我们,在使用交错数组分析项目时,也应该使用交错数组而不是多维数组。简单地说,多维数组类似于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表格:
将上述情况视为每行的列数可变:
多维数组创建了一个很好的线性内存布局,而锯齿状数组意味着多个间接级别 在锯齿状数组中查找值
jagged[3][6]
var jagged=new int[10][5]
的工作方式如下:在索引3处查找元素(这是一个数组),在该数组中的索引6处查找元素(这是一个值)。对于本例中的每个维度,都有一个额外的查找(这是一种昂贵的内存访问模式)
多维数组在内存中线性排列,实际值是通过将索引相乘得到的。但是,给定数组var mult=new int[10,30]
,该多维数组的Length
属性返回元素总数,即10*30=300
锯齿数组的Rank
属性始终为1,但多维数组可以有任何秩。任何数组的GetLength
方法都可以用来获取每个维度的长度。对于本例中的多维数组,mult.GetLength(1)
返回30
索引多维数组的速度更快。e、 g.给定本例中的多维数组mult[1,7]
=30*1+7=37,获取该索引37处的元素。这是一种更好的内存访问模式,因为只涉及一个内存位置,即阵列的基址
因此,多维数组分配连续内存块,而锯齿数组不必是正方形,例如锯齿[1]。长度不必等于锯齿[2]。长度,这对于任何多维数组都是正确的
演出
就性能而言,多维阵列应该更快。速度要快得多,但由于CLR实现非常糟糕,所以它们不是
23.084 16.634 15.215 15.489 14.407 13.691 14.695 14.398 14.551 14.252
25.782 27.484 25.711 20.844 19.607 20.349 25.861 26.214 19.677 20.171
5.050 5.085 6.412 5.225 5.100 5.751 6.650 5.222 6.770 5.305
第一行是锯齿状数组的计时,第二行显示多维数组,第三行,应该是这样的。该程序如下所示,仅供参考。该程序在运行mono时进行了测试。(由于CLR实现的不同,windows的时间安排有很大的不同)
在windows上,锯齿状数组的计时非常优越,这与我自己对多维数组查找的解释大致相同,请参见“Single()”。遗憾的是,windows JIT编译器真的很愚蠢,不幸的是,这使得这些性能讨论变得困难,存在太多的不一致
这些是我在windows上得到的计时,这里的处理是一样的,第一行是锯齿状数组,第二行是多维数组,第三行是我自己的多维数组实现,请注意,与mono相比,windows上的执行速度要慢得多
8.438 2.004 8.439 4.362 4.936 4.533 4.751 4.776 4.635 5.864
7.414 13.196 11.940 11.832 11.675 11.811 11.812 12.964 11.885 11.751
11.355 10.788 10.527 10.541 10.745 10.723 10.651 10.930 10.639 10.595
源代码:
using System;
using System.Diagnostics;
static class ArrayPref
{
const string Format = "{0,7:0.000} ";
static void Main()
{
Jagged();
Multi();
Single();
}
static void Jagged()
{
const int dim = 100;
for(var passes = 0; passes < 10; passes++)
{
var timer = new Stopwatch();
timer.Start();
var jagged = new int[dim][][];
for(var i = 0; i < dim; i++)
{
jagged[i] = new int[dim][];
for(var j = 0; j < dim; j++)
{
jagged[i][j] = new int[dim];
for(var k = 0; k < dim; k++)
{
jagged[i][j][k] = i * j * k;
}
}
}
timer.Stop();
Console.Write(Format,
(double)timer.ElapsedTicks/TimeSpan.TicksPerMillisecond);
}
Console.WriteLine();
}
static void Multi()
{
const int dim = 100;
for(var passes = 0; passes < 10; passes++)
{
var timer = new Stopwatch();
timer.Start();
var multi = new int[dim,dim,dim];
for(var i = 0; i < dim; i++)
{
for(var j = 0; j < dim; j++)
{
for(var k = 0; k < dim; k++)
{
multi[i,j,k] = i * j * k;
}
}
}
timer.Stop();
Console.Write(Format,
(double)timer.ElapsedTicks/TimeSpan.TicksPerMillisecond);
}
Console.WriteLine();
}
static void Single()
{
const int dim = 100;
for(var passes = 0; passes < 10; passes++)
{
var timer = new Stopwatch();
timer.Start();
var single = new int[dim*dim*dim];
for(var i = 0; i < dim; i++)
{
for(var j = 0; j < dim; j++)
{
for(var k = 0; k < dim; k++)
{
single[i*dim*dim+j*dim+k] = i * j * k;
}
}
}
timer.Stop();
Console.Write(Format,
(double)timer.ElapsedTicks/TimeSpan.TicksPerMillisecond);
}
Console.WriteLine();
}
}
使用系统;
使用系统诊断;
静态类ArrayPref
{
常量字符串格式=“{0,7:0.000}”;
静态void Main()
{
锯齿状();
多重();
单个();
}
静态空洞锯齿状()
{
常数int dim=100;
对于(var过程=0;过程<10;过程++)
{
var timer=新秒表();
timer.Start();
var jagged=新整数[dim][];
对于(变量i=0;i 23.084 16.634 15.215 15.489 14.407 13.691 14.695 14.398 14.551 14.252
25.782 27.484 25.711 20.844 19.607 20.349 25.861 26.214 19.677 20.171
5.050 5.085 6.412 5.225 5.100 5.751 6.650 5.222 6.770 5.305
8.438 2.004 8.439 4.362 4.936 4.533 4.751 4.776 4.635 5.864
7.414 13.196 11.940 11.832 11.675 11.811 11.812 12.964 11.885 11.751
11.355 10.788 10.527 10.541 10.745 10.723 10.651 10.930 10.639 10.595
using System;
using System.Diagnostics;
static class ArrayPref
{
const string Format = "{0,7:0.000} ";
static void Main()
{
Jagged();
Multi();
Single();
}
static void Jagged()
{
const int dim = 100;
for(var passes = 0; passes < 10; passes++)
{
var timer = new Stopwatch();
timer.Start();
var jagged = new int[dim][][];
for(var i = 0; i < dim; i++)
{
jagged[i] = new int[dim][];
for(var j = 0; j < dim; j++)
{
jagged[i][j] = new int[dim];
for(var k = 0; k < dim; k++)
{
jagged[i][j][k] = i * j * k;
}
}
}
timer.Stop();
Console.Write(Format,
(double)timer.ElapsedTicks/TimeSpan.TicksPerMillisecond);
}
Console.WriteLine();
}
static void Multi()
{
const int dim = 100;
for(var passes = 0; passes < 10; passes++)
{
var timer = new Stopwatch();
timer.Start();
var multi = new int[dim,dim,dim];
for(var i = 0; i < dim; i++)
{
for(var j = 0; j < dim; j++)
{
for(var k = 0; k < dim; k++)
{
multi[i,j,k] = i * j * k;
}
}
}
timer.Stop();
Console.Write(Format,
(double)timer.ElapsedTicks/TimeSpan.TicksPerMillisecond);
}
Console.WriteLine();
}
static void Single()
{
const int dim = 100;
for(var passes = 0; passes < 10; passes++)
{
var timer = new Stopwatch();
timer.Start();
var single = new int[dim*dim*dim];
for(var i = 0; i < dim; i++)
{
for(var j = 0; j < dim; j++)
{
for(var k = 0; k < dim; k++)
{
single[i*dim*dim+j*dim+k] = i * j * k;
}
}
}
timer.Stop();
Console.Write(Format,
(double)timer.ElapsedTicks/TimeSpan.TicksPerMillisecond);
}
Console.WriteLine();
}
}
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]
.method private hidebysig instance uint32[0...,0...]
GenerateWorkingKey(uint8[] key,
bool forEncryption) cil managed
Debug (code optimalization disabled)
Running jagged
187.232 200.585 219.927 227.765 225.334 222.745 224.036 222.396 219.912 222.737
Running multi-dimensional
130.732 151.398 131.763 129.740 129.572 159.948 145.464 131.930 133.117 129.342
Running single-dimensional
91.153 145.657 111.974 96.436 100.015 97.640 94.581 139.658 108.326 92.931
Release (code optimalization enabled)
Running jagged
108.503 95.409 128.187 121.877 119.295 118.201 102.321 116.393 125.499 116.459
Running multi-dimensional
62.292 60.627 60.611 60.883 61.167 60.923 62.083 60.932 61.444 62.974
Running single-dimensional
34.974 33.901 34.088 34.659 34.064 34.735 34.919 34.694 35.006 34.796
Debug:
(Jagged)
5.616 4.719 4.778 5.524 4.559 4.508 5.913 6.107 5.839 5.270
(Multi)
6.336 7.477 6.124 5.817 6.516 7.098 5.272 6.091 25.034 6.023
(Single)
4.688 3.494 4.425 6.176 4.472 4.347 4.976 4.754 3.591 4.403
Release(code optimizations on):
(Jagged)
2.614 2.108 3.541 3.065 2.172 2.936 1.681 1.724 2.622 1.708
(Multi)
3.371 4.690 4.502 4.153 3.651 3.637 3.580 3.854 3.841 3.802
(Single)
1.934 2.102 2.246 2.061 1.941 1.900 2.172 2.103 1.911 1.911