1. Зубчасті масиви відрізняються від двовимірних
Отже, ми дійшли до теми, яку часто називають «зубчастими масивами» — англійською — jagged arrays. На відміну від двовимірних масивів, зубчасті масиви дозволяють зберігати рядки різної довжини. Це можна уявити як комплекс будівель, кожна з яких має свою кількість квартир: в одній будівлі 5 квартир, в іншій — 20, а у третій — лише одна.
Зубчастий масив — масив, у якому кожен елемент — теж масив, причому вкладені масиви (їх ще називають «підмасивами») можуть мати різну довжину.
Головна відмінність:
- У двовимірному масиві кожен «рядок» (і кожен «стовпець») має однакову кількість елементів. Приклад: int[][] grid = new int[3][5]; — у нас завжди 3 рядки по 5 елементів.
- У зубчастому масиві кожен рядок може мати різну довжину. Приклад: int[][] jagged = new int[3][]; — а вже потім ми кожен рядок (підмасив) ініціалізуємо по‑своєму.
Ось як це виглядає візуально:
Двовимірний масив (3x3):
┌───┬───┬───┐
│ 1 │ 2 │ 3 │
├───┼───┼───┤
│ 4 │ 5 │ 6 │
├───┼───┼───┤
│ 7 │ 8 │ 9 │
└───┴───┴───┘
Зубчастий масив (різні довжини):
┌───┬───┐
│ 1 │ 2 │
├───┼───┼───┬───┐
│ 3 │ 4 │ 5 │ 6 │
├───┼───┴───┴───┘
│ 7 │
└───┘
2. Синтаксис оголошення та ініціалізації зубчастого масиву
Оголошення зубчастого масиву не складніше за оголошення інших масивів. Лякатися подвійних квадратних дужок не варто:
int[][] jaggedArray = new int[3][];
Це означає, що маємо масив із 3 елементів, і кожен із них — також масив типу int. Поки що внутрішні масиви не створені. Для кращого розуміння розгляньмо детальніше.
Покрокова ініціалізація зубчастого масиву
Крок 1 — створення основного (зовнішнього) масиву:
int[][] jaggedArray = new int[3][];
Тепер у нас є 3 «рядки», але всі вони поки що дорівнюють null.
Крок 2 — створення й заповнення внутрішніх масивів (підмасивів):
Наприклад, нехай перший рядок буде довжиною 2, другий — 4, третій — 3:
jaggedArray[0] = new int[2]; // 2 елементи у першому рядку
jaggedArray[1] = new int[4]; // 4 елементи у другому рядку
jaggedArray[2] = new int[3]; // 3 елементи у третьому рядку
Крок 3 — заповнення значеннями:
Внутрішні масиви — це звичайні масиви. Наприклад:
jaggedArray[0][0] = 1;
jaggedArray[0][1] = 2;
jaggedArray[1][0] = 3;
jaggedArray[1][1] = 4;
jaggedArray[1][2] = 5;
jaggedArray[1][3] = 6;
jaggedArray[2][0] = 7;
jaggedArray[2][1] = 8;
jaggedArray[2][2] = 9;
Скорочена ініціалізація зубчастого масиву
Можна створити й заповнити зубчастий масив одразу, якщо ви знаєте значення заздалегідь:
int[][] jaggedArray = new int[][]
{
new int[] { 1, 2 },
new int[] { 3, 4, 5, 6 },
new int[] { 7, 8, 9 }
};
Або трохи коротше, опускаючи тип внутрішніх масивів:
int[][] jaggedArray =
{
{ 1, 2 },
{ 3, 4, 5, 6 },
{ 7, 8, 9 }
};
3. Перебирання та робота із зубчастими масивами
Ітерувати зубчастий масив не складніше, ніж двовимірний: зовнішній цикл проходить рядками, а внутрішній — елементами рядка (їхня довжина може різнитися):
for (int i = 0; i < jaggedArray.length; i++)
{
System.out.println("Рядок " + i + ":");
for (int j = 0; j < jaggedArray[i].length; j++)
{
System.out.print(jaggedArray[i][j] + " ");
}
System.out.println();
}
Результат на екрані:
Рядок 0:
1 2
Рядок 1:
3 4 5 6
Рядок 2:
7 8 9
Можна використати for-each, щоб не відстежувати індекси:
for (int[] row : jaggedArray)
{
for (int value : row)
{
System.out.print(value + " ");
}
System.out.println();
}
4. Типові сценарії застосування зубчастих масивів
Коли зубчастий масив може бути кориснішим за двовимірний?
- Якщо ви зберігаєте для кожного користувача різну кількість даних: оцінки з предметів, покупки, коментарі тощо.
- Якщо ваші дані мають трикутну або східчасту структуру (наприклад, для виведення пірамід, трикутників Паскаля тощо).
- Якщо хочете заощаджувати памʼять: у двовимірному масиві всі рядки фіксованої довжини, а в зубчастому — лише потрібна кількість елементів для кожного рядка.
Приклад із життя: менеджер оцінок студентів
Припустімо, у нас є три студенти, і ось їхні оцінки за різні завдання з математики:
| Студент | Оцінки |
|---|---|
| 0 | 5, 4 |
| 1 | 3, 4, 4 |
| 2 | 5 |
Оголосимо такий масив:
int[][] studentMarks = new int[3][];
studentMarks[0] = new int[] { 5, 4 }; // Перший студент — 2 оцінки
studentMarks[1] = new int[] { 3, 4, 4 }; // Другий студент — 3 оцінки
studentMarks[2] = new int[] { 5 }; // Третій студент — 1 оцінка
Виведемо оцінки кожного студента:
for (int i = 0; i < studentMarks.length; i++)
{
System.out.print("Студент " + i + ": ");
for (int j = 0; j < studentMarks[i].length; j++)
{
System.out.print(studentMarks[i][j] + " ");
}
System.out.println();
}
Використання зубчастих масивів із іншими типами
Зубчастим може бути масив чого завгодно: рядків, масивів інших масивів (глибше!), навіть ваших власних об’єктів.
Приклад: масив рядків
String[][] groups = {
{ "Іван", "Петро" },
{ "Марія", "Олексій", "Сергій" },
{ "Василиса" }
};
5. Тривимірні та багатовимірні масиви
І ще один цікавий факт про масиви, про який ви, мабуть, уже здогадуєтеся: якщо можна зробити двовимірний масив, то можна зробити й тривимірний.
Так, можна створити масив будь-якої розмірності. Такі масиви називають багатовимірними.
Як оголошувати багатовимірні масиви
Достатньо просто вказати потрібну кількість розмірів у квадратних дужках:
int[][][] cube = new int[2][3][4]; // 2 «шари», 3 рядки, 4 стовпці
cube[0][1][2] = 99;
Тут у нас тривимірний масив:
- 2 елементи за першою координатою,
- 3 — за другою,
- 4 — за третьою.
Такий масив — це один великий «куб» даних, упакований послідовно.
Перебирання тривимірного масиву
Доступ до елемента здійснюється за всіма індексами одразу:
for (int i = 0; i < cube.length; i++)
{
for (int j = 0; j < cube[i].length; j++)
{
for (int k = 0; k < cube[i][j].length; k++)
{
System.out.print(cube[i][j][k] + " ");
}
System.out.println();
}
System.out.println("---");
}
- Індекси нумеруються з нуля, як завжди у Java.
- Усього в такому масиві буде 2 × 3 × 4 = 24 елементи.
Практичні приклади багатовимірних масивів
- 2D — таблиці, шахові дошки, зображення.
- 3D — «кубики» у компʼютерній графіці, дані для наукових розрахунків (наприклад, температура в різних точках простору та часу).
- 4D і вище — рідко використовуються, але трапляються в просунутій математиці, симуляціях, машинному навчанні тощо.
6. Типові помилки під час роботи з багатовимірними масивами
Помилка № 1: Вихід за межі масиву
Найпоширеніша помилка — спроба звернутися до неіснуючого елемента, наприклад:
int[][] arr = new int[2][3];
arr[2][0] = 5; // Помилка! Немає рядка з індексом 2 (є лише 0 і 1)
arr[0][3] = 7; // Помилка! Немає стовпця з індексом 3 (є лише 0, 1, 2)
За такого звернення програма викине виняток ArrayIndexOutOfBoundsException. Завжди перевіряйте, що індекси в допустимих межах: від 0 до length - 1.
Помилка № 2: Неініціалізовані рядки в зубчастому масиві
Якщо створити зубчастий масив і забути ініціалізувати внутрішні масиви, під час звернення буде NullPointerException:
int[][] jagged = new int[3][];
jagged[0][0] = 5; // Помилка! jagged[0] == null
Спочатку треба створити внутрішній масив: jagged[0] = new int[2];
Помилка № 3: Некоректне використання довжини масиву
Плутають matrix.length (кількість рядків) і matrix[0].length (кількість стовпців). Особливо часто — під час копіювання, перебирання або підсумовування за стовпцями.
Помилка № 4: Припущення, що всі рядки однакової довжини
У зубчастих масивах рядки можуть бути різної довжини. Якщо ви пишете matrix[i][j], переконайтеся, що j < matrix[i].length.
Помилка № 5: Плутанина в порядку індексів
Іноді плутають порядок індексів: спочатку йде рядок, а потім стовпець — matrix[рядок][стовпець], а не навпаки.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ