Mapuj tablicę 2D na tablicę 1D

91

Chcę przedstawić tablicę 2D z tablicą 1D. Funkcja przekaże dwa wskaźniki (x, y) i wartość do zapamiętania. Te dwa wskaźniki reprezentowałyby pojedynczy element tablicy 1D i odpowiednio go ustawiały. Wiem, że tablica 1D musi mieć rozmiar arrayWidth × arrayHeight, ale nie wiem, jak ustawić każdy element.

Na przykład, jak odróżnić (2,4,3) od (4,2,3)? Próbowałem ustawić tablicę jako x * y, ale 2 * 4 i 4 * 2 dałyby to samo miejsce w tablicy i potrzebuję, aby były różne.

Blackbinary
źródło

Odpowiedzi:

165

Musisz zdecydować, czy elementy tablicy będą przechowywane w kolejności wierszy, czy kolumn, a następnie zachować spójność. http://en.wikipedia.org/wiki/Row-major_order

Język C używa kolejności wierszy dla tablic wielowymiarowych

Aby zasymulować to za pomocą jednowymiarowej tablicy, należy pomnożyć indeks wiersza przez szerokość i dodać indeks kolumny w ten sposób:

 int array[width * height];

 int SetElement(int row, int col, int value)
 {
    array[width * row + col] = value;  
 }
John Knoeller
źródło
7
Myślę, że ta odpowiedź jest jaśniejsza, zwłaszcza dla początkujących lepiej nie pisać funkcji w jednej linii ... !! To i tak zła praktyka .. :)
Lipis
3
Ta odpowiedź jest również przydatna, gdy masz kompilator (np. Systemy wbudowane), który nie ma odpowiedniej obsługi wielowymiarowych tablic
Alex Marshall,
1
To niesamowite, jak wiele osób może poprawnie odpowiedzieć na to samo pytanie, ale tylko JEDNA z nich mówi to w łatwy do zrozumienia sposób. Odpowiedź jest tak prosta, jak to tylko możliwe. Jednak John jest jedyną osobą, która faktycznie udzieliła na to dobrej odpowiedzi. Cała reszta to śmieci, które mogą być łatwo zrozumiane tylko przez tych, którzy już znają odpowiedź. Dzięki Johnowi, że właściwie mówiłeś po angielsku zamiast obcego. To tylko pokazuje, jak kiepsko jest niektórzy ludzie w nauczaniu i jak dobrzy nauczyciele, tacy jak John Knoeller, wiedzą, jak upraszczać i komunikować się znacznie skuteczniej niż wszyscy inni.
user2948630
6
Byłoby dobrze, aby pokazać, jak odwrócić ten mapowanie: jeśli indeks tablicy 1D alphai 2D tablica ma wymiar Nw obydwu kierunkach z indeksami x, y, a następnie zgodnie z @JohnKnoeller, alpha=x+N*y. Sposobem na odwrócenie tego byłoby ustawienie x=alpha%Ni y= (alpha-alpha%N)/N.
Tim
Przyjeżdżam tu prawie codziennie!
Felipe Gutierrez
23

Typowa formuła przeliczania indeksów tablicy 2D na indeks tablicy 1D to

index = indexX * arrayWidth + indexY;

Alternatywnie możesz użyć

index = indexY * arrayHeight + indexX;

(zakładając, że arrayWidthjest mierzona wzdłuż osi X iarrayHeight wzdłuż osi Y)

Oczywiście można wymyślić wiele różnych formuł, które zapewniają alternatywne unikalne odwzorowania, ale zwykle nie ma takiej potrzeby.

W językach C / C ++ wbudowane tablice wielowymiarowe są przechowywane w pamięci, dzięki czemu ostatni indeks zmienia się najszybciej, co oznacza, że ​​dla tablicy zadeklarowanej jako

int xy[10][10];

xy[5][3]zaraz po elemencie następuje xy[5][4]w pamięci. Możesz również przestrzegać tej konwencji, wybierając jedną z dwóch powyższych formuł w zależności od tego, który indeks (X lub Y) uważasz za „ostatni” z nich.

Mrówka
źródło
17

Przykład: chcemy przedstawić tablicę 2D o rozmiarach SIZE_X i SIZE_Y. Oznacza to, że będziemy mieć MAXY kolejnych rzędów o rozmiarze MAXX. Stąd ustawioną funkcją jest

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

Wynik byłby:

int get_array( int x, int y ) { return array[ x * SIZE_Y + y ]; }
Kornel Kisielewicz
źródło
1
Twoje MAXXi MAXYwartości są myląco nazwane, ponieważ maksymalne wartości xi ysą odpowiednio MAXX - 1i MAXY - 1. Może SIZE_Xi SIZE_Ymoże być lepiej?
kawiarnia
3
[y * maxx + x] to kolejność kolumn, a nie kolejność wierszy. Tak działa Matlab, ale nie jest to sposób, w jaki tablice działają normalnie w C.
John Knoeller,
@everyone: chyba, że ​​dane są dotykane, ale tylko te dwie funkcje get / set i używają tej samej formuły, możesz to zrobić tak, jak TO lub TAK. (Gwarantowane!)
imacake
Makro może być tutaj bardziej odpowiednie, aby nie układać w stosy niepotrzebnych wywołań funkcji na tym, co ma być dostępem do danych niskiego poziomu (zwłaszcza, że ​​indeksowanie 1d w tablicach pseudo-2d jest czasami techniką optymalizacji.
krs013
Zakładając, że kod jest członkiem klasy, ten kod zostanie wstawiony. W przeciwnym razie jawne inline jest DUŻO lepsze niż makro.
Kornel Kisielewicz
7

Jak powiedzieli inni, mapy C w porządku wierszowym

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

Wynik:

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
źródło
3

używając głównego przykładu wiersza:

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
źródło
1

Ważne jest, aby przechowywać dane w sposób umożliwiający ich pobranie w używanych językach. Język C przechowuje w kolejności głównej wiersza (najpierw pierwszy wiersz, potem cały drugi wiersz, ...) z każdym indeksem zaczynającym się od 0 do jego wymiaru-1. Zatem kolejność tablicy x [2] [3] to x [0] [0], x [0] [1], x [0] [2], x [1] [0], x [1] [ 1], x [1] [2]. Zatem w języku C x [i] [j] jest przechowywane w tym samym miejscu co jednowymiarowa pozycja tablicy x1dim [i * 3 + j]. Jeśli dane są przechowywane w ten sposób, można je łatwo pobrać w języku C.

Fortran i MATLAB są różne. Przechowują się w kolejności według kolumn (cała pierwsza kolumna jest pierwsza, potem cała druga kolumna, ...), a każdy indeks zaczyna się od 1 do swojego wymiaru. Więc kolejność indeksów jest odwrotnością C i wszystkie indeksy są o 1 większe. Jeśli przechowujesz dane w kolejności języka C, FORTRAN może znaleźć X_C_language [i] [j] za pomocą X_FORTRAN (j + 1, i + 1). Na przykład X_C_language [1] [2] jest równe X_FORTRAN (3,2). W tablicach jednowymiarowych ta wartość danych to X1dim_C_language [2 * Cdim2 + 3], czyli ta sama pozycja co X1dim_FORTRAN (2 * Fdim1 + 3 + 1). Pamiętaj, że Cdim2 = Fdim1, ponieważ kolejność indeksów jest odwrócona.

MATLAB to to samo, co FORTRAN. Ada jest tym samym, co C, z tym wyjątkiem, że indeksy zwykle zaczynają się od 1. Każdy język będzie miał indeksy w jednym z tych zleceń C lub FORTRAN, a indeksy zaczną się od 0 lub 1 i można je odpowiednio dostosować, aby uzyskać przechowywane dane.

Przepraszam, jeśli to wyjaśnienie jest mylące, ale myślę, że jest dokładne i ważne dla programisty.

znak
źródło
-2

Powinieneś być w stanie uzyskać dostęp do tablicy 2D za pomocą prostego wskaźnika w miejscu. Tablica [x] [y] zostanie umieszczona we wskaźniku jako p [0x * szerokość + 0y] [0x * szerokość + 1y] ... [0x * szerokość + n-1y] [1x * szerokość + 0y] itd. .

Arthur Kalliokoski
źródło