Складіть 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.