Asignar una matriz 2D a una matriz 1D

90

Quiero representar una matriz 2D con una matriz 1D. Una función pasará los dos índices (x, y) y el valor para almacenar. Estos dos índices representarían un solo elemento de una matriz 1D y lo establecerían en consecuencia. Sé que la matriz 1D debe tener el tamaño de arrayWidth × arrayHeight, pero no sé cómo configurar cada elemento.

Por ejemplo, ¿cómo distingo (2,4,3) de (4,2,3)? Intenté configurar la matriz como x * y, pero 2 * 4 y 4 * 2 darían como resultado el mismo lugar en la matriz y necesito que sean diferentes.

Blackbinary
fuente

Respuestas:

164

Debe decidir si los elementos de la matriz se almacenarán en orden de fila o en orden de columna y luego ser coherente al respecto. http://en.wikipedia.org/wiki/Row-major_order

El lenguaje C usa el orden de las filas para matrices multidimensionales

Para simular esto con una matriz unidimensional, multiplique el índice de fila por el ancho y agregue el índice de columna así:

 int array[width * height];

 int SetElement(int row, int col, int value)
 {
    array[width * row + col] = value;  
 }
John Knoeller
fuente
7
Creo que esta respuesta es más clara, especialmente para los principiantes, ¡es mejor no escribir funciones en una línea ...! De todos modos, es una mala práctica .. :)
Lipis
3
Esta respuesta también es útil para cuando tiene un compilador (por ejemplo, sistemas integrados) que no tiene el soporte de matriz multidimensional adecuado
Alex Marshall
1
Es sorprendente cuántas personas pueden responder correctamente la misma pregunta, pero solo UNA de ellas lo dice de una manera fácil de entender. Esta es una respuesta tan simple como parece. Sin embargo, John es el único que realmente da una buena respuesta. Todo lo demás es basura que solo pueden entender fácilmente aquellos que ya conocen la respuesta. Gracias John, por hablar en inglés en lugar de en alienígena. Solo sirve para mostrar lo malos que son algunas personas en la enseñanza y cómo los buenos maestros como John Knoeller saben cómo simplificar y comunicarse de manera mucho más efectiva que todos los demás.
user2948630
6
Sería bueno para mostrar Cómo invertir este mapeo: si el índice de la matriz 1D es alpha, y la matriz de 2D tiene dimensión Nen ambas direcciones con índices x, y, a continuación, de acuerdo con @JohnKnoeller, alpha=x+N*y. La forma de invertir esto sería establecer x=alpha%Ny y= (alpha-alpha%N)/N.
Tim
¡Vengo aquí casi todos los días!
Felipe Gutierrez
23

La fórmula típica para volver a calcular los índices de matriz 2D en un índice de matriz 1D es

index = indexX * arrayWidth + indexY;

Alternativamente, puede usar

index = indexY * arrayHeight + indexX;

(asumiendo que arrayWidthse mide a lo largo del eje X y a lo arrayHeightlargo del eje Y)

Por supuesto, se pueden encontrar muchas fórmulas diferentes que brinden asignaciones únicas alternativas, pero normalmente no es necesario.

En los lenguajes C / C ++, las matrices multidimensionales integradas se almacenan en la memoria para que el último índice cambie más rápido, lo que significa que para una matriz declarada como

int xy[10][10];

elemento xy[5][3]es seguido inmediatamente por xy[5][4]en la memoria. Es posible que desee seguir esa convención también, eligiendo una de las dos fórmulas anteriores según el índice (X o Y) que considere el "último" de los dos.

Hormiga
fuente
17

Ejemplo: queremos representar una matriz 2D de tamaño SIZE_X y SIZE_Y. Eso significa que tendremos MAXY filas consecutivas de tamaño MAXX. Por tanto, la función de conjunto es

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

El get sería:

int get_array( int x, int y ) { return array[ x * SIZE_Y + y ]; }
Kornel Kisielewicz
fuente
1
Sus valores MAXXy MAXYse nombran de manera confusa, porque los valores máximos de xy yson MAXX - 1y MAXY - 1respectivamente. ¿Quizás SIZE_Xy SIZE_Ypodría ser mejor?
Café
3
[y * maxx + x] es el orden de las columnas, no de las filas. Esta es la forma en que funciona matlab, pero no es la forma en que las matrices funcionan normalmente en C.
John Knoeller
@todos: a menos que mantenga los datos tocados, pero simplemente estas dos funciones get / set, y usen la misma fórmula, puede hacerlo así o ASÍ. (¡Garantizado!)
imacake
Una macro podría ser más apropiada aquí para no apilar llamadas de función innecesarias en lo que se supone que es un acceso a datos de bajo nivel (especialmente porque la indexación 1d en matrices pseudo-2d es a veces una técnica de optimización.
krs013
Suponiendo que el código es un miembro de la clase, este código se incluirá. De lo contrario, una línea explícita es MUCHO mejor que una macro.
Kornel Kisielewicz
7

Como otros han dicho, mapas C en orden de fila

   #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]);
         }
       } 
    } 

Salida:

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
fuente
3

usando el ejemplo de fila principal:

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
fuente
1

Es importante almacenar los datos de manera que se puedan recuperar en los idiomas utilizados. El lenguaje C se almacena en orden de fila principal (toda la primera fila viene primero, luego toda la segunda fila, ...) con cada índice desde 0 hasta su dimensión-1. Entonces, el orden de la matriz x [2] [3] es x [0] [0], x [0] [1], x [0] [2], x [1] [0], x [1] [ 1], x [1] [2]. Entonces, en lenguaje C, x [i] [j] se almacena en el mismo lugar que una entrada de matriz unidimensional x1dim [i * 3 + j]. Si los datos se almacenan de esa manera, es fácil recuperarlos en lenguaje C.

Fortran y MATLAB son diferentes. Se almacenan en orden de columna principal (toda la primera columna viene primero, luego toda la segunda fila, ...) y cada índice va desde 1 hasta su dimensión. Entonces, el orden del índice es el inverso de C y todos los índices son 1 mayor. Si almacena los datos en el orden del lenguaje C, FORTRAN puede encontrar X_C_language [i] [j] usando X_FORTRAN (j + 1, i + 1). Por ejemplo, X_C_language [1] [2] es igual a X_FORTRAN (3,2). En matrices unidimensionales, ese valor de datos está en X1dim_C_language [2 * Cdim2 + 3], que es la misma posición que X1dim_FORTRAN (2 * Fdim1 + 3 + 1). Recuerde que Cdim2 = Fdim1 porque el orden de los índices se invierte.

MATLAB es lo mismo que FORTRAN. Ada es igual que C excepto que los índices normalmente comienzan en 1. Cualquier idioma tendrá los índices en una de esas órdenes C o FORTRAN y los índices comenzarán en 0 o 1 y se pueden ajustar en consecuencia para obtener los datos almacenados.

Disculpe si esta explicación es confusa, pero creo que es precisa e importante que un programador la sepa.

marca
fuente
-2

Debería poder acceder a la matriz 2d con un simple puntero en su lugar. La matriz [x] [y] se organizará en el puntero como p [0x * ancho + 0y] [0x * ancho + 1y] ... [0x * ancho + n-1y] [1x * ancho + 0y] etc. .

Arthur Kalliokoski
fuente