2011-03-29 7 views
10

Il s'agit essentiellement d'une reformulation de cette question: Java: Multi-dimensional array vs. One-dimensional mais pour C#.Tableau multidimensionnel vs. Unidimensionnel

J'ai une quantité définie d'éléments qui ont un sens pour stocker en tant que grille. Dois-je utiliser un tableau [x * y] ou un tableau [x] [y]?

EDIT: Oh, donc il y a un tableau unidimensionnel [x * y], un tableau multidimensionnel [x, y] et un tableau en dents de scie [x] [y], et je veux probablement un jagged?

+1

Je marquer le tableau '' multidimensional' comme tableau [x, y] 'au lieu de' array [x] [y] ' – Snowbear

Répondre

10

Il y a de nombreux avantages en C# à utiliser jagged arrays (array[][]). En fait, ils surpasseront souvent les tableaux multidimensionnels. Cela dit, j'utiliserais personnellement un tableau multidimensionnel ou irrégulier au lieu d'un tableau unidimensionnel, car cela correspond plus étroitement à l'espace problème. L'utilisation d'un tableau à une dimension ajoute à votre implémentation une complexité qui ne procure pas de réels avantages, en particulier par rapport à un tableau 2D, car en interne, il s'agit toujours d'un seul bloc de mémoire.

+3

Désolé, mais je déteste ce terme "tableaux Jagged". La documentation de .net jette tellement de terminologie que quelqu'un penserait qu'un tableau déchiqueté était un nouveau type de données. C'est juste un tableau de tableau dangit! – JonH

+3

@JonH: Oui, mais c'est le terme officiel pour cela, et il y a des optimisations spécifiques en place dans le CLR pour travailler avec eux. –

9

Plus de array[x,y]:
- Runtime effectuer plus de contrôles pour vous. Chaque accès à l'index sera vérifié pour être dans la plage autorisée. Avec une autre approche, vous pouvez facilement faire comme a[y*numOfColumns + x] où x peut être plus que "nombre de colonnes" et ce code va extraire une valeur erronée sans lancer d'exception.
- Accès plus clair à l'index. a[x,y] est plus propre que a[y*numOfColumns + x]

Plus de array[x*y]:
- plus facile itération sur l'ensemble du réseau. Vous n'avez besoin que d'une boucle au lieu de deux.

Et gagnant est ... Je préférerais array[x,y]

11

J'ai couru un test sur les tableaux déraisonnablement grandes et été surpris de voir que les tableaux crénelées ([y] [x]) semblent être plus rapide que la tableau à une dimension avec multiplication manuelle [y * ySize + x]. Et les tableaux multidimensionnels [,] sont plus lents mais pas tellement. Bien sûr, vous devrez tester sur vos tableaux en particulier, mais il semblerait que le différent n'est pas beaucoup, donc vous devriez simplement utiliser quelle approche correspond à ce que vous faites le mieux.

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

Poste très intéressant. J'ai trouvé le ProfileTimer sur code.google.com. Au début, je ne pouvais pas reproduire vos résultats. L'allocation de mémoire pour le tableau en dents de scie était très lente et l'accès 2-dim était très lent. Ensuite, j'ai décoché "Préférez 32 bits" dans les options de construction et tout correspondait de très près à vos résultats. – dcaswell

Questions connexes