1. Двовимірні масиви
І ще один цікавий факт про масиви. Масиви бувають не лише лінійними, а й двовимірними.
І що це означає, спитаєте ви?
А це означає, що комірки масиву можна представити не лише у вигляді стовпчика (або рядка), але й у вигляді прямокутної таблиці.
int[][] ім'я = new int[ширина][висота];
Де ім'я — це ім'я змінної-масиву, ширина — це ширина таблиці (в комірках), а висота — це висота таблиці. Приклад:
|
Створюємо двовимірний масив: два стовпці та 5 рядків. У комірку (1,1) записуємо 5. |
Ось як це виглядатиме в пам'яті:
До речі, для двовимірних масивів можна також використовувати швидку ініціалізацію:
// довжина місяців року поквартально
int[][] months = { {31, 28, 31}, {30, 31, 30}, {31, 31, 30}, {31, 30, 31} };
Є дуже багато місць, де вам як програмісту може знадобитися двовимірний масив. Реалізація практично будь-якої настільної гри — це ж готовий двовимірний масив: «Шахи», «Шашки», «Хрестики-Нулики», «Морський бій»:
Ігрове поле «Шахів» або «Морського бою» таке, що воно просто ідеально лягає на двовимірні масиви, тільки як координати клітин потрібно буде використовувати лише числа. Не «пішака e2 -> e4», а «пішака (4,1) -> (4,3)». Вам як програмісту буде навіть простіше.
2. Розташування елементів у масивах: (x,y) чи (y,x)
Тут, до речі, є цікава дилема:
Коли ми створюємо масив new int[2][5]; у нас таблиця «два рядки і 5 стовпців» чи все-таки «два стовпці і 5 рядків»? Іншими словами, ми спочатку задаємо «ширину», а потім «висоту» чи все-таки спочатку «висоту», а потім — «ширину»? І, як кажуть, тут не все так однозначно.
Почнемо з питання: а як ця таблиця реально зберігається в пам'яті?
У самій пам'яті комп’ютера жодних таблиць немає: всі байти пам’яті пронумеровані як 0, 1, 2, ... Це для нас таблиця 2×5, а в пам’яті це просто 10 комірок і все. Без розділення, де рядки, а де стовпці.
Аргумент на користь гіпотези «ширина»-«висота».
Ще у школі всіх учили, що з пари координат спочатку вказується «x», а потім «y». І це не просто шкільний стандарт — це взагалі стандарт у математиці. Проти цариці наук, як кажуть, не попреш. Тобто? Спочатку «ширина», а потім «висота»?
Аргумент на користь гіпотези «висота»- «ширина».
Тут також є цікавий аргумент і йде він із... швидкої ініціалізації двовимірних масивів. Адже якщо ми захочемо ініціалізувати наш масив, напишемо цей код так:
// Важлива матриця з даними
int[][] matrix = { {1, 2, 3, 4, 5}, {1, 2, 3, 4, 5} };
Нічого не помітили? А якщо так:
// Важлива матриця з даними
int[][] matrix = {
{1, 2, 3, 4, 5},
{1, 2, 3, 4, 5}
};
Якщо ми напишемо наші дані в коді построчно, то отримаємо таблицю, у якої 2 рядки і 5 стовпців.
Результати
Що тут скажеш? Вам вирішувати, як вам зручніше. Головне, щоб усі програмісти, які працюють над одним проєктом, дотримувалися одного підходу.
Якщо ви будете працювати над проєктом, де багато ініціалізованих двовимірних масивів у коді, то, найімовірніше, там всі будуть відштовхуватися від швидкої ініціалізації даних і буде стандарт «висота»-«ширина».
Якщо ж вам пощастить потрапити в проєкт, де багато математики і працюють з координатами (наприклад, робота з ігровими рушіями), там, найімовірніше, будуть дотримуватися підходу «ширина»-«висота»
3. Пристрій двовимірних масивів
А зараз ви дізнаєтесь, як насправді влаштовані двовимірні масиви. Готові?
Двовимірні масиви — це насправді масиви масивів!
Іншими словами, якщо у випадку зі звичайним масивом «змінна-масив зберігає посилання на контейнер, який зберігає елементи масиву». То у випадку з двовимірними масивами у нас ситуація трохи вибухонебезпечніша: змінна-двовимірний-масив зберігає посилання на контейнер, який зберігає посилання на одномірні масиви. Це краще один раз побачити, ніж сто разів спробувати пояснити:
Зліва у нас «змінна-двовимірний-масив», яка зберігає посилання на «об’єкт-двовимірний масив». У середині у нас «об’єкт двовимірний масив», в комірках якого зберігаються посилання на одномірні масиви — рядки двовимірного масиву. Ну і праворуч ви бачите чотири одномірних масиви — рядки нашого двовимірного масиву.
Це те, як насправді влаштовані двовимірні масиви. І такий підхід дає Java-програмісту кілька переваг:
По-перше, оскільки «контейнер контейнерів» зберігає посилання на «масиви-рядки», ми можемо дуже швидко і просто міняти рядки місцями. Щоб отримати доступ до «контейнера контейнерів», потрібно просто вказати один індекс замість двох. Приклад:
int[][] data = new int[2][5];
int[] row1 = data[0];
int[] row2 = data[1];
Ось за допомогою такого коду можна змінювати рядки місцями:
|
Двовимірний масив У matrix[0] у нас зберігається посилання на перший рядок.Міняємо посилання місцями. У результаті масив matrix виглядає так: |
Якщо ви звертаєтесь до комірки двовимірного масиву, але після імені масиву вказуєте лише один індекс, ви таким чином звернетесь до контейнера-контейнерів, у комірках якого зберігаються посилання на звичайні одномірні масиви.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ