Mapper un tableau 2D sur un tableau 1D

91

Je veux représenter un tableau 2D avec un tableau 1D. Une fonction passera les deux indices (x, y) et la valeur à stocker. Ces deux indices représenteraient un élément unique d'un tableau 1D et le définiraient en conséquence. Je sais que le tableau 1D doit avoir la taille de arrayWidth × arrayHeight, mais je ne sais pas comment définir chaque élément.

Par exemple, comment distinguer (2,4,3) de (4,2,3)? J'ai essayé de définir le tableau comme x * y, mais 2 * 4 et 4 * 2 aboutiraient au même endroit dans le tableau et j'ai besoin qu'ils soient différents.

Blackbinary
la source

Réponses:

166

Vous devez décider si les éléments du tableau seront stockés dans l'ordre des lignes ou des colonnes, puis être cohérent à ce sujet. http://en.wikipedia.org/wiki/Row-major_order

Le langage C utilise l'ordre des lignes pour les tableaux multidimensionnels

Pour simuler cela avec un tableau à une seule dimension, vous multipliez l'index de ligne par la largeur et ajoutez l'index de colonne ainsi:

 int array[width * height];

 int SetElement(int row, int col, int value)
 {
    array[width * row + col] = value;  
 }
John Knoeller
la source
7
Je pense que cette réponse est plus claire, surtout pour les débutants il vaut mieux ne pas écrire les fonctions sur une seule ligne ... !! C'est une mauvaise pratique quand même .. :)
Lipis
3
Cette réponse est également utile lorsque vous avez un compilateur (par exemple des systèmes embarqués) qui ne prend pas en charge correctement les tableaux multidimensionnels
Alex Marshall
1
Il est étonnant de voir combien de personnes peuvent répondre correctement à la même question, mais une seule d'entre elles le dit d'une manière facile à comprendre. C'est une réponse aussi simple que possible. Cependant, John est le seul à fournir une bonne réponse. Tout le reste est une poubelle qui ne peut être facilement comprise que par ceux qui connaissent déjà la réponse. Merci John, d'avoir parlé en anglais au lieu d'étranger. Cela montre à quel point certaines personnes enseignent mal et à quel point de bons enseignants comme John Knoeller savent comment simplifier et communiquer beaucoup plus efficacement que tout le monde.
user2948630
6
Il serait bon de montrer comment inverser cette mise en correspondance: si l'indice du tableau 1D est alpha, et le tableau 2D a une dimension Ndans les deux sens avec des indices x, y, puis selon @JohnKnoeller, alpha=x+N*y. La façon d'inverser cela serait de définir x=alpha%Net y= (alpha-alpha%N)/N.
Tim
Je viens ici presque tous les jours!
Felipe Gutierrez
23

La formule typique pour recalculer les indices de tableau 2D en index de tableau 1D est

index = indexX * arrayWidth + indexY;

Vous pouvez également utiliser

index = indexY * arrayHeight + indexX;

(en supposant qu'il arrayWidthest mesuré le long de l'axe X et le arrayHeightlong de l'axe Y)

Bien sûr, on peut trouver de nombreuses formules différentes qui fournissent des mappages uniques alternatifs, mais normalement ce n'est pas nécessaire.

Dans les langages C / C ++, les tableaux multidimensionnels intégrés sont stockés en mémoire afin que le dernier index change le plus rapidement, ce qui signifie que pour un tableau déclaré comme

int xy[10][10];

L'élément xy[5][3]est immédiatement suivi par xy[5][4]en mémoire. Vous voudrez peut-être également suivre cette convention, en choisissant l'une des deux formules ci-dessus en fonction de l'index (X ou Y) que vous considérez comme le "dernier" des deux.

Fourmi
la source
17

Exemple: nous voulons représenter un tableau 2D de taille SIZE_X et SIZE_Y. Cela signifie que nous aurons MAXY lignes consécutives de taille MAXX. Par conséquent, la fonction définie est

void set_array( int x, int y, int val ) { array[ x * SIZE_Y + y ] = val; }

Le get serait:

int get_array( int x, int y ) { return array[ x * SIZE_Y + y ]; }
Kornel Kisielewicz
la source
1
Votre MAXXetMAXY valeurs sont nommées de manière confuse, car les valeurs maximales de xet ysont respectivement MAXX - 1et MAXY - 1. Peut SIZE_X- être et SIZE_Ypourrait être mieux?
caf
3
[y * maxx + x] est l'ordre des colonnes, pas l'ordre des lignes. C'est ainsi que fonctionne matlab, mais ce n'est pas la façon dont les tableaux fonctionnent normalement dans C.
John Knoeller
@everyone: à moins que vous ne gardiez les données touchées, mais uniquement ces deux fonctions get / set, et qu'elles utilisent la même formule, vous pouvez le faire comme CECI ou comme CELA. (Garanti!)
imacake
Une macro peut être plus appropriée ici afin de ne pas empiler des appels de fonction inutiles sur ce qui est censé être un accès aux données de bas niveau (d'autant plus que l'indexation 1d dans des tableaux pseudo-2D est parfois une technique d'optimisation.
krs013
En supposant que le code est un membre de la classe, ce code sera incorporé. Sinon, en ligne explicite est BEAUCOUP mieux qu'une macro.
Kornel Kisielewicz
7

Comme d'autres l'ont dit, les cartes C dans l'ordre des lignes

   #include <stdio.h>

   int main(int argc, char **argv) {
   int i, j, k;
   int arr[5][3];
   int *arr2 = (int*)arr;

       for (k=0; k<15; k++) {
          arr2[k] = k;
          printf("arr[%d] = %2d\n", k, arr2[k]);
       }

       for (i=0; i<5; i++) {
         for (j=0; j< 3; j++) {
            printf("arr2[%d][%d] = %2d\n", i, j ,arr[i][j]);
         }
       } 
    } 

Production:

arr[0] =  0
arr[1] =  1
arr[2] =  2
arr[3] =  3
arr[4] =  4
arr[5] =  5
arr[6] =  6
arr[7] =  7
arr[8] =  8
arr[9] =  9
arr[10] = 10
arr[11] = 11
arr[12] = 12
arr[13] = 13
arr[14] = 14
arr2[0][0] =  0
arr2[0][1] =  1
arr2[0][2] =  2
arr2[1][0] =  3
arr2[1][1] =  4
arr2[1][2] =  5
arr2[2][0] =  6
arr2[2][1] =  7
arr2[2][2] =  8
arr2[3][0] =  9
arr2[3][1] = 10
arr2[3][2] = 11
arr2[4][0] = 12
arr2[4][1] = 13
arr2[4][2] = 14
Sammy
la source
3

en utilisant l'exemple de ligne principale:

A(i,j) = a[i + j*ld]; // where ld is the leading dimension
                      // (commonly same as array dimension in i)

// matrix like notation using preprocessor hack, allows to hide indexing
#define A(i,j) A[(i) + (j)*ld]

double *A = ...;
size_t ld = ...;
A(i,j) = ...;
... = A(j,i);
Anycorn
la source
1

Il est important de stocker les données de manière à pouvoir les récupérer dans les langues utilisées. Le langage C stocke dans l'ordre des lignes principales (toute la première ligne vient en premier, puis toute la deuxième ligne, ...) avec chaque index allant de 0 à sa dimension-1. Ainsi l'ordre du tableau x [2] [3] est x [0] [0], x [0] [1], x [0] [2], x [1] [0], x [1] [ 1], x [1] [2]. Ainsi, en langage C, x [i] [j] est stocké au même endroit qu'une entrée de tableau à 1 dimension x1dim [i * 3 + j]. Si les données sont stockées de cette façon, il est facile de les récupérer en langage C.

Fortran et MATLAB sont différents. Ils stockent dans l'ordre principal de la colonne (toute la première colonne vient en premier, puis toute la deuxième ligne, ...) et chaque index va de 1 à sa dimension. Ainsi, l'ordre des indices est l'inverse de C et tous les indices sont 1 plus grands. Si vous stockez les données dans l'ordre du langage C, FORTRAN peut trouver X_C_language [i] [j] en utilisant X_FORTRAN (j + 1, i + 1). Par exemple, X_C_language [1] [2] est égal à X_FORTRAN (3,2). Dans les tableaux à 1 dimension, cette valeur de données est à X1dim_C_language [2 * Cdim2 + 3], qui est la même position que X1dim_FORTRAN (2 * Fdim1 + 3 + 1). Rappelez-vous que Cdim2 = Fdim1 car l'ordre des indices est inversé.

MATLAB est le même que FORTRAN. Ada est identique à C sauf que les indices commencent normalement à 1. Toute langue aura les indices dans l'un de ces ordres C ou FORTRAN et les indices commenceront à 0 ou 1 et peuvent être ajustés en conséquence pour obtenir les données stockées.

Désolé si cette explication est déroutante, mais je pense qu'elle est précise et importante pour un programmeur.

marque
la source
-2

Vous devriez pouvoir accéder au tableau 2d avec un simple pointeur en place. Le tableau [x] [y] sera arrangé dans le pointeur comme p [0x * largeur + 0y] [0x * largeur + 1y] ... [0x * largeur + n-1y] [1x * largeur + 0y] etc. .

Arthur Kalliokoski
la source