ступенчатый - В чем разница между многомерным массивом и массивом массивов в C#?




ступенчатый массив c# (6)

В дополнение к другим ответам обратите внимание, что многомерный массив выделяется как один большой кусок объекта в куче. Это имеет некоторые последствия:

  1. Некоторые многомерные массивы получат выделение в кучке больших объектов (LOH), где в противном случае их эквивалентные дробленые массивные копии не имели бы.
  2. GC должен будет найти единый непрерывный свободный блок памяти для размещения многомерного массива, тогда как зубчатый массив может заполнить пробелы, вызванные фрагментацией кучи ... это обычно не проблема в .NET из-за уплотнения , но LOH не уплотняется по умолчанию (вы должны спросить об этом, и вы должны спросить каждый раз, когда вы этого хотите).
  3. Вы захотите заглянуть в <gcAllowVeryLargeObjects> для многомерных массивов , прежде чем проблема когда-либо возникнет, если вы когда-либо используете только зубчатые массивы.

В чем разница между многомерными массивами double[,] и array-of-arrays double[][] в C #?

Если есть разница, для чего лучше всего использовать?


Массив массивов (зубчатых массивов) быстрее, чем многомерные массивы, и их можно использовать более эффективно. Многомерные массивы имеют более хороший синтаксис.

Если вы напишете какой-нибудь простой код, используя неровные и многомерные массивы, а затем проверите скомпилированную сборку с дизассемблером 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;
}

Их ИЛ будет выглядеть следующим образом:

.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 говорит, что вместо использования многогранных массивов, когда вы используете его для анализа ваших проектов, следует использовать неровные массивы.


Многомерными массивами являются (n-1) -размерные матрицы.

Итак, int[,] square = new int[2,2] - квадратная матрица 2x2, int[,,] cube = new int [3,3,3] - квадратная матрица 3x3. Пропорциональность не требуется.

Жесткие массивы - это всего лишь массив массивов - массив, в котором каждая ячейка содержит массив.

Таким образом, MDA пропорциональны, JD может и не быть! Каждая ячейка может содержать массив произвольной длины!


Проще говоря, многомерные массивы подобны таблице в СУБД.
Массив массива (массив с зазубринами) позволяет каждому элементу удерживать другой массив того же типа переменной длины.

Итак, если вы уверены, что структура данных выглядит как таблица (фиксированные строки / столбцы), вы можете использовать многомерный массив. Jagged 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

Я разбираю файлы .il, сгенерированные ildasm, для создания базы данных assemnblies, классов, методов и хранимых процедур для использования, выполняющих преобразование. Я наткнулся на следующее, что нарушило мой синтаксический анализ.

.method private hidebysig instance uint32[0...,0...] 
        GenerateWorkingKey(uint8[] key,
                           bool forEncryption) cil managed

Книга Expert .NET 2.0 IL Assembler, автор: Serge Lidin, Apress, опубликованная в 2006 году, глава 8, «Примитивные типы и подписи», стр. 149-150.

<type>[] называется Vector <type> ,

<type>[<bounds> [<bounds>**] ] называется массивом <type>

** означает повторение, [ ] означает необязательный.

Примеры: Пусть <type> = int32 .

1) int32[...,...] - это двумерный массив неопределенных нижних границ и размеров

2) int32[2...5] является одномерным массивом нижних границ 2 и размера 4.

3) int32[0...,0...] - двумерный массив нижних границ 0 и неопределенный размер.

Том


Я хотел бы обновить это, потому что в .NET Core многомерные массивы быстрее, чем зубчатые массивы . Я провел тесты у Джона Лейдегрена, и это результаты в .NET Framework 2.0. 2. Я увеличил значение измерения, чтобы сделать любые возможные влияния из фоновых приложений менее заметными.

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 

Я искал разборки, и вот что я нашел

jagged[i][j][k] = i * j * k; необходимо 34 инструкции для выполнения

multi[i, j, k] = i * j * k; требуется 11 инструкций для выполнения

single[i * dim * dim + j * dim + k] = i * j * k; требуется 23 инструкции для выполнения

Я не смог определить, почему одномерные массивы все еще быстрее, чем многомерные, но я предполагаю, что это связано с некоторой оптимизацией, сделанной на CPU





jagged-arrays