Складіть 2D-масив на 1D-масив


90

Я хочу представити 2D-масив з 1D-масивом. Функція передаватиме два індекси (x, y) та значення, яке потрібно зберегти. Ці два індикатори представляли б окремий елемент 1D-масиву та встановлювали його відповідно. Я знаю, що 1D-масив повинен мати розмір arrayWidth × arrayHeight, але я не знаю, як встановити кожен елемент.

Наприклад, як я можу відрізнити (2,4,3) від (4,2,3)? Я спробував встановити масив як x * y, але 2 * 4 і 4 * 2 призвели б до того самого місця в масиві, і мені потрібно, щоб вони були різними.

Відповіді:


163

Вам потрібно вирішити, чи будуть елементи масиву зберігатися в порядку рядків або в порядку стовпців, а потім бути послідовними щодо цього. http://en.wikipedia.org/wiki/Row-major_order

Мова C використовує порядок рядків для багатовимірних масивів

Щоб імітувати це за допомогою одновимірного масиву, ви помножуєте індекс рядка на ширину і додаєте індекс стовпця таким чином:

 int array[width * height];

 int SetElement(int row, int col, int value)
 {
    array[width * row + col] = value;  
 }

7
Я думаю, що ця відповідь є більш зрозумілою, особливо для початківців краще не писати функції в один рядок ... !! Це все одно погана практика .. :)
Ліпис

3
Ця відповідь також корисна, якщо у вас є компілятор (наприклад, вбудовані системи), який не має належної підтримки багатовимірного масиву
Alex Marshall

1
Дивно, як багато людей можуть правильно відповісти на одне і те ж питання, але лише ОДИН із них говорить це так, щоб це було легко зрозуміти. Відповідь така проста. Однак Джон єдиний, хто насправді дав на це хорошу відповідь. Все інше - це сміття, яке легко зрозуміти лише тим, хто вже знає відповідь. Дякую, Джон, що насправді розмовляв англійською, а не іноземною. Це просто показує, наскільки деякі люди погано навчають, і як такі добрі вчителі, як Джон Ноеллер, вміють спрощувати та спілкуватися набагато ефективніше за всіх.
user2948630

6
Було б добре , щоб показати , як звернути це відображення: якщо індекс масиву 1D є alphaі 2D масив має розмірність Nв обох напрямках з індексами x, y, то згідно @JohnKnoeller, alpha=x+N*y. Шляхом інвертувати це буде встановлення x=alpha%Nі y= (alpha-alpha%N)/N.
Тім

Я приходжу сюди майже щодня!
Феліпе Гутьєррес

23

Типовою формулою для перерахунку 2D-індексів масиву в 1D-індекс-масив є

index = indexX * arrayWidth + indexY;

Ви також можете використовувати

index = indexY * arrayHeight + indexX;

(припускаючи, що arrayWidthвимірюється вздовж осі X та arrayHeightвздовж осі Y)

Звичайно, можна придумати безліч різних формул, що забезпечують альтернативні унікальні зіставлення, але зазвичай немає необхідності.

У мовах C / C ++ вбудовані багатовимірні масиви зберігаються в пам'яті так, що останній індекс змінюється найшвидше, що означає, що для масиву, оголошеного як

int xy[10][10];

за елементом xy[5][3]відразу слідує xy[5][4]в пам'яті. Можливо, ви також захочете дотримуватися цієї домовленості, вибравши одну з двох наведених вище формул, залежно від того, який індекс (X або Y) ви вважаєте "останнім" з них.


17

Приклад: ми хочемо представити 2D-масив розміром SIZE_X та SIZE_Y. Це означає, що у нас буде MAXY послідовних рядків розміром MAXX. Отже, задана функція є

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

Отримати буде:

int get_array( int x, int y ) { return array[ x * SIZE_Y + y ]; }

1
Ваші значення MAXXта MAXYзначення заплутано названі, оскільки максимальні значення xі yє, MAXX - 1і MAXY - 1відповідно. Можливо, SIZE_Xі SIZE_Yможе бути краще?
кафе

3
[y * maxx + x] - порядок стовпців, а не порядок рядків. Це спосіб роботи
matlab

@everyone: якщо ви не тримаєте дані в контакті, але суто ці дві функції отримання / встановлення, і вони використовують ту саму формулу, ви можете зробити це як ЦЕ або як ТО (Гарантовано!)
imacake

Тут макрос може бути більш доречним, щоб ви не клали непотрібні виклики функцій на, як передбачається, доступ до даних низького рівня (тим більше, що 1d-індексація в псевдо-2d-масивах іноді є технікою оптимізації.
krs013

Якщо припустити, що код є членом класу, цей код буде вбудований. В іншому випадку явний вбудований НАБАГАТО кращий за макрос.
Kornel Kisielewicz

7

Як сказали інші, C-карти в порядку рядків

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

Вихід:

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

3

використовуючи основний приклад рядка:

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);

1

Важливо зберігати дані таким чином, щоб їх можна було отримати на використовуваних мовах. Мова на мові З зберігається у великому порядку (перший перший рядок стоїть першим, потім весь другий рядок, ...), при цьому кожен індекс працює від 0 до його розмірності 1. Отже, порядок масиву x [2] [3] дорівнює x [0] [0], x [0] [1], x [0] [2], x [1] [0], x [1] [ 1], x [1] [2]. Отже, мовою C, x [i] [j] зберігається там же, де і 1-мірний запис масиву x1dim [i * 3 + j]. Якщо дані зберігаються таким чином, їх легко отримати мовою C.

Fortran і MATLAB відрізняються. Вони зберігаються у порядку основного стовпця (перший перший стовпець стоїть першим, потім весь другий рядок, ...), і кожен індекс працює від 1 до його розміру. Отже, порядок індексів є зворотним до C, і всі індекси на 1 більші. Якщо ви зберігаєте дані в мовному порядку на мові C, FORTRAN може знайти X_C_language [i] [j] за допомогою X_FORTRAN (j + 1, i + 1). Наприклад, X_C_language [1] [2] дорівнює X_FORTRAN (3,2). В одновимірних масивах це значення даних має значення X1dim_C_language [2 * Cdim2 + 3], що відповідає позиції X1dim_FORTRAN (2 * Fdim1 + 3 + 1). Пам'ятайте, що Cdim2 = Fdim1, оскільки порядок індексів зворотний.

MATLAB - те саме, що FORTRAN. Ada - це те саме, що C, за винятком того, що індекси зазвичай починаються з 1. Будь-яка мова матиме індекси в одному з цих замовлень C або FORTRAN, а індекси починатимуться з 0 або 1 і можуть бути відповідно налаштовані для отримання збережених даних.

Вибачте, якщо це пояснення бентежить, але я думаю, що це точно і важливо для програміста знати.


-2

Ви повинні мати доступ до 2d-масиву за допомогою простого вказівника на місці. Масив [x] [y] буде розташовано в покажчику як p [0x * width + 0y] [0x * width + 1y] ... [0x * width + n-1y] [1x * width + 0y] тощо .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.