C# 多维数组与一维数组

C# 多维数组与一维数组,c#,arrays,performance,multidimensional-array,C#,Arrays,Performance,Multidimensional Array,这基本上是对这个问题的重申:但对于C# 我有一定数量的元素可以存储为网格。 我应该使用数组[x*y]还是数组[x][y] 编辑:哦,所以有一维数组[x*y],多维数组[x,y]和锯齿状数组[x][y],我可能想要锯齿状?使用(array[][])C有很多优点。实际上,它们的性能通常优于多维数组 也就是说,我个人会使用多维数组或锯齿数组,而不是一维数组,因为这与问题空间的匹配更紧密。使用一维数组会增加实现的复杂性,但这并不能带来真正的好处,尤其是与二维数组相比,因为在内部,它仍然是一个单一的内存块

这基本上是对这个问题的重申:但对于C#

我有一定数量的元素可以存储为网格。 我应该使用数组[x*y]还是数组[x][y]


编辑:哦,所以有一维数组[x*y],多维数组[x,y]和锯齿状数组[x][y],我可能想要锯齿状?

使用(
array[][]
)C有很多优点。实际上,它们的性能通常优于多维数组


也就是说,我个人会使用多维数组或锯齿数组,而不是一维数组,因为这与问题空间的匹配更紧密。使用一维数组会增加实现的复杂性,但这并不能带来真正的好处,尤其是与二维数组相比,因为在内部,它仍然是一个单一的内存块。

数组[x,y]的优点:
-运行时将为您执行更多检查。将检查每个索引访问是否在允许范围内。使用另一种方法,您可以轻松地执行smth,如
a[y*numocolumns+x]
,其中x可以大于“列数”,并且此代码将提取一些错误值而不会引发异常。
-更清晰的索引访问
a[x,y]
a[y*numOfColumns+x]

数组[x*y]的优点

-在整个阵列上更容易迭代。您只需要一个循环,而不是两个


获胜者是…我更喜欢
数组[x,y]
我对不合理的大数组进行了测试,惊讶地发现锯齿数组([y][x])似乎比手动乘法的一维数组[y*ySize+x]更快。多维数组[,]的速度较慢,但相差不大

当然,您必须在特定的阵列上进行测试,但是看起来差别不大,所以您应该使用适合您所做的最好的方法

0.280 (100.0% | 0.0%) 'Jagged array 5,059x5,059 - 25,593,481'
|       0.006 (2.1% | 2.1%) 'Allocate'
|       0.274 (97.9% | 97.9%) 'Access'


0.336 (100.0% | 0.0%) 'TwoDim array 5,059x5,059 - 25,593,481'
|       0.000 (0.0% | 0.0%) 'Allocate'
|       0.336 (99.9% | 99.9%) 'Access'


0.286 (100.0% | 0.0%) 'SingleDim array 5,059x5,059 - 25,593,481'
|       0.000 (0.1% | 0.1%) 'Allocate'
|       0.286 (99.9% | 99.9%) 'Access'



0.552 (100.0% | 0.0%) 'Jagged array 7,155x7,155 - 51,194,025'
|       0.009 (1.6% | 1.6%) 'Allocate'
|       0.543 (98.4% | 98.4%) 'Access'


0.676 (100.0% | 0.0%) 'TwoDim array 7,155x7,155 - 51,194,025'
|       0.000 (0.0% | 0.0%) 'Allocate'
|       0.676 (100.0% | 100.0%) 'Access'


0.571 (100.0% | 0.0%) 'SingleDim array 7,155x7,155 - 51,194,025'
|       0.000 (0.1% | 0.1%) 'Allocate'
|       0.571 (99.9% | 99.9%) 'Access'



for (int i = 6400000; i < 100000000; i *= 2)
{
    int size = (int)Math.Sqrt(i);
    int totalSize = size * size;

    GC.Collect();

    ProfileTimer.Push(string.Format("Jagged array {0:N0}x{0:N0} - {1:N0}", size, totalSize));

    ProfileTimer.Push("Allocate");

    double[][] Jagged = new double[size][];
    for (int x = 0; x < size; x++)
    {
        Jagged[x] = new double[size];
    }

    ProfileTimer.PopPush("Allocate", "Access");

    double total = 0;
    for (int trials = 0; trials < 10; trials++)
    {
        for (int y = 0; y < size; y++)
        {
            for (int x = 0; x < size; x++)
            {
                total += Jagged[y][x];
            }
        }
    }

    ProfileTimer.Pop("Access");
    ProfileTimer.Pop("Jagged array");


    GC.Collect();

    ProfileTimer.Push(string.Format("TwoDim array {0:N0}x{0:N0} - {1:N0}", size, totalSize));

    ProfileTimer.Push("Allocate");

    double[,] TwoDim = new double[size,size];

    ProfileTimer.PopPush("Allocate", "Access");

    total = 0;
    for (int trials = 0; trials < 10; trials++)
    {
        for (int y = 0; y < size; y++)
        {
            for (int x = 0; x < size; x++)
            {
                total += TwoDim[y, x];
            }
        }
    }

    ProfileTimer.Pop("Access");
    ProfileTimer.Pop("TwoDim array");


    GC.Collect();

    ProfileTimer.Push(string.Format("SingleDim array {0:N0}x{0:N0} - {1:N0}", size, totalSize));

    ProfileTimer.Push("Allocate");

    double[] Single = new double[size * size];

    ProfileTimer.PopPush("Allocate", "Access");

    total = 0;
    for (int trials = 0; trials < 10; trials++)
    {
        for (int y = 0; y < size; y++)
        {
            int yOffset = y * size;
            for (int x = 0; x < size; x++)
            {
                total += Single[yOffset + x];
            }
        }
    }

    ProfileTimer.Pop("Access");
    ProfileTimer.Pop("SingleDim array");
}
0.280(100.0%| 0.0%)“锯齿阵列5059x5059-25593481”
|0.006(2.1%| 2.1%)“分配”
|0.274(97.9%| 97.9%)“准入”
0.336(100.0%| 0.0%)“TwoDim阵列5059x5059-25593481”
|0.000(0.0%| 0.0%)“分配”
|0.336(99.9%| 99.9%)“访问”
0.286(100.0%| 0.0%)“单芯阵列5059x5059-25593481”
|0.000(0.1%| 0.1%)“分配”
|0.286(99.9%| 99.9%)“访问”
0.552(100.0%| 0.0%)“锯齿阵列7155x7155-51194025”
|0.009(1.6%| 1.6%)“分配”
|0.543(98.4%| 98.4%)“准入”
0.676(100.0%| 0.0%)“双色阵列7155x7155-51194025”
|0.000(0.0%| 0.0%)“分配”
|0.676(100.0%| 100.0%)“准入”
0.571(100.0%| 0.0%)“单芯阵列7155x7155-51194025”
|0.000(0.1%| 0.1%)“分配”
|0.571(99.9%| 99.9%)“访问”
对于(整数i=6400000;i<100000000;i*=2)
{
int size=(int)Math.Sqrt(i);
int totalSize=大小*大小;
GC.Collect();
ProfileTimer.Push(string.Format(“锯齿数组{0:N0}x{0:N0}-{1:N0}”,size,totalSize));
ProfileTimer.Push(“分配”);
双精度[]锯齿形=新的双精度[尺寸][];
用于(int x=0;x
对不起,我讨厌“锯齿阵列”这个词。net文档抛出了太多术语,以至于有人会认为锯齿数组是一种新的数据类型。这只是一个数组而已@John:是的,但这是官方术语,在CLR中有一些特定的优化,可以用来处理它们。我会将
多维
数组标记为
数组[x,y]
而不是
数组[x][y]
锯齿状数组对Linq来说更容易理解。非常有趣的帖子。我在code.google.com上找到了ProfileTimer。起初我无法复制你的结果。锯齿阵列的内存分配非常慢,2维访问非常慢。然后我在构建选项中取消选中“偏好32位”,所有内容都与您的结果非常匹配。