JavaRush /Java блог /Random UA /Багатовимірні масиви

Багатовимірні масиви

Стаття з групи Random UA
Багатовимірні масиви - 1

Що таке одновимірний масив Java?

Масив — це впорядкована множина елементів одного типу, примітивного або посилального. Загальну інформацію про масиви (переважно одномірні) можна знайти в статті " Масиви в Java " і в курсі JavaRush . У цій статті йтиметься про масиви, елементами яких є інші масиви. Такі масиви називаються багатовимірними. Масив, елементами якого є інші масиви, тобто масив масивів, називається двовимірним. Не у всіх мовах багатовимірні масиви мають таку структуру, але в Java справи саме так.

Багатовимірні масиви Java, загальний синтаксис

В узагальненому вигляді багатовимірні масиви Java виглядають так:
Data_type[dimension1][dimension2][]..[dimensionN] array_name = new data_type[size1][size2].[sizeN];
Де Data_type– це тип елементів у масиві. Може бути примітивним чи посилальним (класом). Кількість пар дужок із dimensionвсередині – розмірність масиву (у нашому випадку – N). array_name- Назва масиву size1...sizN- Кількість елементів у кожному з вимірювань масиву. Оголошення багатовимірних масивів:
int[][] twoDimArray; //двовимірний масив
String[][][] threeDimArray; //трьохвимірний масив
double[][][][][] fiveDimArray; //П'ятимірний масив
Можливо, все це виглядає дуже абстрактно, тому тепер перейдемо до конкретних проявів багатовимірних масивів – двовимірних та тривимірних. Справа в тому, що Java-розробники іноді користуються двовимірними масивами, набагато рідше - тривимірними, а масиви ще більшої розмірності - надзвичайно рідкісні. З великою часткою ймовірності ви з ними не стикатиметеся.

Багатомірні масиви в курсі JavaRush

На JavaRush до "простих" масивів приступають на 7 рівні квесту Java Syntax і далі по ходу курсу вони зустрічаються неодноразово. Іноді протягом курсу трапляються завдання на двовимірні масиви (або такі, які можна вирішити за допомогою). А ще двовимірні масиви використані в двигуні ігор спеціального розділу " Ігри на JavaRush ". Якщо ви ще там не були, загляньте та створіть пару-трійку ігор. До умов додаються докладні інструкції, і це стане прекрасним тренуванням навичок програмування. Тривимірний масив можна знайти у грі Space Invaders. Через нього задається набір фреймів для анімації (і кожен із цих фреймів — двовимірний масив). Якщо ви вже пройшли квест JavaSyntax або просто впевнено почуваєтеся в програмуванні на Java, спробуйте написати власну версію цієї класичної гри.

Що таке двовимірний масив Java?

Двовимірний масив в Java - це масив масивів, тобто в кожному його осередку знаходиться посилання на якийсь масив. Але набагато простіше його у вигляді таблиці, яка має кількість рядків (перший вимір) і кількість стовпців (другий вимір). Двовимірний масив, у якого всі рядки мають рівну кількість елементів, називається прямокутним.

Оголошення, створення та ініціалізація двовимірних масивів

Процедура оголошення та створення двовимірного масиву практично така сама, як і у випадку одновимірного:
int[][] twoDimArray = new int[3][4];
Цей масив має 3 рядки та 4 стовпці. Розмір прямокутного двовимірного масиву (вони можуть і не бути прямокутними, про це трохи нижче), тобто загальну кількість елементів можна визначити, перемноживши кількість рядків на кількість стовпців. Наразі він проініціалізований (заповнений) значеннями за умовчанням. Тобто нулями. Давайте заповнимо його потрібними значеннями.
twoDimArray[0][0] = 5;//записали значення 5 в комірку на перетині нульового рядка та нульового стовпця
twoDimArray[0][1] = 7; //записали значення 7 в комірку на перетині нульового рядка та першого стовпця
twoDimArray[0][2]  = 3;
twoDimArray[0][3] = 17;
twoDimArray[1][0] = 7;
twoDimArray[1][1] = 0;
twoDimArray[1][2] = 1;
twoDimArray[1][3] = 12;
twoDimArray[2][0] = 8;
twoDimArray[2][1] = 1;
twoDimArray[2][2] = 2;
twoDimArray[2][3] = 3;
Як і у випадку з одновимірними масивами, можна провести процедуру ініціалізації швидше:
int [][] twoDimArray = {{5,7,3,17}, {7,0,1,12}, {8,1,2,3}};
І в тому, і в іншому випадку ми отримаємо двовимірний масив із трьома рядками та чотирма стовпцями, заповнений цілими числами. Багатовимірні масиви - 2

Виведення двовимірного масиву на екран

Цю операцію логічніше робити так: спочатку виводимо нульовий рядок поелементно, потім — другий і так далі. Найчастіше Java виведення двовимірного масиву реалізують за допомогою двох вкладених циклів.
int [][] twoDimArray = {{5,7,3,17}, {7,0,1,12}, {8,1,2,3}};//Оголосабо масив і заповнабо його елементами
for (int i = 0; i < 3; i++) {  //Йдемо по рядках
            for (int j = 0; j < 4; j++) {//ідемо стовпцями
                System.out.print(" " + twoDimArray[i][j] + " "); //Виведення елемента
            }
            System.out.println();//перенесення рядка для візуального збереження табличної форми
        }

Швидкий висновок двовимірного масиву

Найкоротший спосіб вивести список елементів двовимірного масиву на екран – застосування методу deepToStringкласу Arrays. Приклад:
int[][] myArray = {{18,28,18},{28,45,90},{45,3,14}};
System.out.printLn(Arrays.deepToString(myArray));
Результат роботи програми - наступний висновок: [[18, 28, 18], [28, 45, 90], [45, 3, 14]]

"Довжини" двовимірного масиву

Щоб отримати довжину одновимірного масиву (тобто кількість елементів у ньому), можна використовувати змінну length. Тобто, якщо ми визначимо масив int a[] = {1,2,3}, то операція a.lengthповертає 3. А що, якщо цю процедуру застосувати до нашого двовимірного масиву?
int [][] twoDimArray = {{5,7,3,17}, {7,0,1,12}, {8,1,2,3}};
System.out.println(twoDimArray.length);
Висновок: 3 Таким чином, ця операція виводить кількість рядків у масиві. А як отримати кількість стовпців? Якщо ми маємо справу з прямокутними двовимірними масивами (тобто такими, у яких усі рядки однакової довжини), то можна застосувати операцію twoDimArray[0].lengthабо замість нульового елемента (по суті нульового рядка) будь-який інший існуючий. Ми можемо так вчинити, тому що в Java двомірний масив – це масив масивів, і нульовий елемент twoDimArray[0]– це масив довжини 4. Можете перевірити це самостійно.

Приклад використання двовимірного масиву: шахівниця

Двовимірні масиви можна використовувати для створення будь-якого кінцевого двовимірного поля, наприклад, в іграх і, зокрема, в шахах. Шахову дошку легко уявити у вигляді двовимірного масиву. До цього можна "прикрутити" графіку, а поки що - давайте поставимо шахове поле за допомогою символів і виведемо його в консоль. Багатовимірні масиви - 3Нижня ліва клітина шахівниці пофарбована в чорний колір, наступна за нею — в білий, як і та, що над нею. Отже, колір змінюється щоразу під час переходу на сусідню збоку комірку. Щоб задавати шахове забарвлення не вручну, а за допомогою алгоритму, можна використовувати перевірку на парність: якщо сума індексу рядка і стовпця - парна або нуль, то клітина буде білою, інакше - чорною. Для цієї перевірки в алгоритмі використовуємо оператор залишку від розподілу %. Оскільки ми працюємо не з графікою, а із символами, позначимо білу клітинку буквою W(white), а чорну – буквою B(black).
// задаємо шахівницю двовимірним масивом
String [][] chessBoard = new String[8][8];
        for (int i = 0; i< chessBoard.length; i++) {
            for (int j = 0; j < chessBoard[0].length; j++) {
                if ((i + j) % 2 == 0) chessBoard[i][j] = "W";
                else chessBoard[i][j] = "B";
            }
        }
Виведення програми виходить таке: WBWBWBWBBWBWBWBWWBWBW BWBBWBWBWBWWBWBWBWBBW BWBWBWWBWBWBBWBWBWBW Все як на реальній шахівниці, можете перевірити. Багатовимірні масиви - 4А тепер давайте напишемо метод для правильної нумерації осередків не мовою масивів, а "шаховою" мовою. Нижній лівий осередок на дошці називається А1, тоді як у нашому масиві це — chessBoard[7][0]. Порівняємо кожній парі індексів двовимірного масиву їх “шаховий” еквівалент. Для цього використовуємо два рядки - " abcdefgh" і " 87654321" (у зворотному порядку - для простоти, щоб шахова 8 відповідала нульовому стовпцю).
public static String chessBoardCoord(int a, int b) {
            String letters = "abcdefgh";
            String numbers = "87654321";
            if ((a > 7)|| (b>7)) return null; //якщо номер за межами дошки, повертаємо значення за промовчанням - null
            else return (Character.toString(letters.charAt(a)) + numbers.charAt(b)); /*charAt - метод, за допомогою якого ми витягуємо з рядка елемент під переданим номером, тут - під номерами a та b. Character.toString - метод, який переводить отриманий символ у рядок*/
        }
Тепер виведемо у кожному осередку як її колір, але й її номер, використовуючи методchessBoardCoord
String [][] chessBoard = new String[8][8];
        for (int i = 0; i < chessBoard.length; i++) {
            for (int j = 0; j < chessBoard[0].length; j++) {
                if ((i + j) % 2 == 0) chessBoard[i][j] = "W" + chessBoardCoord(j,i);
                else chessBoard[i][j] = "B"+ chessBoardCoord(j,i);
            }
        }

            for (int i = 0; i < chessBoard.length; i++) {
                for (int j = 0; j < chessBoard[0].length; j++) {
                    System.out.print(" " + chessBoard[i][j] + " ");
                }
                System.out.println();
            }
Виведення програми: Wa8 Bb8 Wc8 Bd8 We8 Bf8 Wg8 Bh8 Ba7 Wb7 Bc7 Wd7 Be7 Wf7 Bg7 Wh7 Wa6 Bb6 Wc6 Bd6 We6 Bf6 Wg6 Bh6 Bc3 Wd3 Be3 Wf3 Bg3 Wh3 Wa2 Bb2 Wc2 Bd2 We2 Bf2 Wg2 Bh2 Ba1 Wb1 Bc1 Wd1 Be1 Wf1 Bg1 Wh1 Де We2означає білу клітинку з номером e2.

Приклад використання двовимірного масиву: множення матриць

Увага!Цей приклад вимагає елементарних знань про матриці. Тут про них буде розказано зовсім небагато, і ця інформація розрахована на тих, хто вивчав, але дещо призабув матричну арифметику. Проте ці знання можна почерпнути з відкритих джерел, зокрема зі статті у Вікіпедії . Це зручний приклад використання двовимірних масивів, але без нього можна рухатися далі. Так що якщо він вам зараз здається незрозумілим з точки зору математики, і ви не дуже хочете заглиблюватися в неї, сміливо пропускайте приклад. Якщо ви вчабо початки лінійної алгебри, можливо, ви дізналися у прямокутних масивах прямокутні матриці. Багатовимірні масиви - 5Де а11, а12 ... aNN - Деякі числа. На малюнку матриця навіть не прямокутна, а квадратна (кількість рядків дорівнює числу стовпців, але це не завжди так). У реальному житті з такими матрицями стикаються рідко, а ось у програмуванні та комп'ютерних науках дуже часто. Зокрема, їх використовують у комп'ютерній графіці та ігрових двигунах. Скажімо, поворот якогось об'єкта на екрані на будь-який кут можна програмувати за допомогою матриці поворотів. У двовимірному просторі матриця поворотів виглядає так: Багатовимірні масиви - 6Де тіта – кут, на який потрібно розгорнути об'єкт. Однакові за розмірністю матриці можна складати між собою, при цьому додавання йде поелементно (складаємо елементи з однаковими індексами). А ось операція множення матриць вже менш звичайна. Так, матриці можна перемножити і отримати матрицю-результат лише якщо кількість стовпців першої матриці збігається з кількістю рядків другого. Матриця-результат матиме стільки рядків, як перша, і стільки ж стовпців, як друга. Множення проводиться наступним чином. Нехай у нас є матриця a[l][m]та b[m][n]. В результаті їх перемноження ми маємо отримати матрицю c[l][n]. Для отримання елемента c[0][0]матриці-твору потрібно нульовий елемент нульового рядка першої матриціa[0][0]перемножити на нульовий елемент другої матриці, потім перший елемент першого рядка першої матриці помножити на перший елемент першого стовпця другої матриці і так далі, після чого всі твори скласти.

a[0][0]*b[0][0] + a[0][1]*b[1][0] + … + a[0][m-1]*b[m-1][0]
Для отримання другого елемента першого рядка матриці-результату виконуємо ту ж процедуру з другим рядком

a[1][0]*b[0][0] + a[1][1]*b[0][1] + … + a[0][m-1]*b[m-1][0]
І так до кінця рядка. Потім переходимо на наступний рядок і повторюємо процедуру, поки рядки у нас не закінчаться. Тобто ми перемножуємо рядки першої матриці зі шпальтами другої матриці. Нижче код для перемноження матриць. Можете його доповнити перевіркою на дотримання згаданої вище умови кількості рядків і стовпців.
//оголошуємо дві матриці
int [][] twoDimArray1 = {{1,0,0,0},{0,1,0,0},{0,0,0,0}};
int[][] twoDimArray2 = {{1,2,3},{1,1,1},{0,0,0},{2,1,0}};

//процес множення матриць
int[][]twoDimArray3 = new int [twoDimArray1.length][twoDimArray2[0].length];
        for (int i=0; i<twoDimArray3[0].length; i++)
            for (int j=0; j<twoDimArray3.length; j++)
                for (k=0; k<twoDimArray1[0].length; k++)
                              twoDimArray3[i][j] = twoDimArray3[i][j] + twoDimArray1[i][k] * twoDimArray2[k][j];

//Виведення на екран
        for (int i = 0; i < twoDimArray3.length; i++) {
            for (int j = 0; j < twoDimArray3[0].length; j++) {
                System.out.print(" " + twoDimArray3[i][j] + " ");
            }
            System.out.println();
        }
Програма виводить наступний результат: 1 2 3 1 1 1 0 0 0

Непрямокутні двовимірні масиви

Оскільки Java двомірні масиви — це масиви масивів, кожен із внутрішніх масивів може бути різної довжини. Створюючи масив, ми можемо вказати лише кількість рядків і не вказувати кількість стовпців (тобто, по суті, довжину цих рядків). Розглянемо приклад.
//оголошуємо і створюємо масив, вказуючи лише кількість рядків
int [][] twoDimArray = new int[5][];

//ініціалізуємо масив, заповнюючи його масивами різної довжини
        twoDimArray[0] = new int[]{1, 2, 3, 4, 5};
        twoDimArray[1] = new int[]{1,2,3,4};
        twoDimArray[2] = new int[]{1,2,3};
        twoDimArray[3] = new int[]{1,2};
        twoDimArray[4] = new int[]{1};
//виведемо непрямокутний двовимірний масив, що вийшов, на екран
        for (int i = 0; i < twoDimArray.length; i++) {
            for (int j = 0; j < twoDimArray[i].length; j++) {
                System.out.print(" " + twoDimArray[i][j] + " ");
            }
            System.out.println();
        }
Висновок програми: 1 2 3 4 5 1 2 3 4 1 2 3 1 2 1 Таким чином, нульовий рядок нашого масиву містить масив {1,2,3,4,5}, а четвертий - масив {1}.

Тривимірні масиви в Java

Дотримуючись здорового глузду та логіки мови Java, тривимірним масивом можна назвати "масив масивів масивів" або "масив, кожним елементом якого є двовимірний масив". До того ж ці двовимірні масиви можуть бути різними. Приклад:
//Створюємо тривимірний масив, що складається з двох двомірних масивів
int[][][] threeDimArr = new int[2][][];
//Створюємо перший двовимірний масив тривимірного масиву розмірністю 5х2
        threeDimArr[0] = new int[5][2];
//Створюємо другий двовимірний масив тривимірного масиву розмірністю 1х1
        threeDimArr[1] = new int[1][1];
Але найчастіше практично зустрічаються тривимірні масиви які всі три величини визначені одночасно, аналог прямокутних двовимірних масивів. Багатовимірні масиви - 7Як ми вже згадували, тривимірні і масивніші використовуються дуже рідко. Проте за допомогою тривимірного масиву можна запрограмувати щось цікаве. Наприклад, багатоповерхове паркування. Кожен поверх можна вважати двовимірним масивом, а паркомісце - конкретним елементом тривимірного масиву. Елемент такого масиву можна представити типом booleanзі значенням false , якщо місце вільне і true , якщо місце зайняте.
//задаємо булев тривимірний масив. На цій парковці є 3 поверхи, на кожному з яких можна розмістити 2х5 = 10 машин. За замовчуванням усі осередки порожні (false)
boolean[][][] parkingLot = new boolean[3][2][5];
//приїхало дві машини і припаркувалися на нульовому поверсі в осередку [1][0] та [1][3]
        parkingLot[0][1][0] = true;
        parkingLot[0][1][3] = true;

//Виведемо масив у консоль
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 2; j++) {
                for (int k = 0; k < 5; k++) {
                    System.out.print("arr[" + i + "][" + j + "][" + k + "] = " + parkingLot[i][j][k] + "\t");

                }
                System.out.println();
            }
        }

Багатовимірні масиви у реальній роботі Java-програміста

Насправді більшість Java-розробників стикаються з багатовимірними масивами не надто часто. Тим не менш, є ряд завдань, для яких ця структура даних підходить дуже непогано.

  1. Для тестів і завдання матриць як констант, щоб перевірити той чи інший алгоритм.
  2. Іноді багатовимірні масиви використовують для нейромереж.
  3. Багатомірні масиви підходять до роботи архіваторів.
  4. Робота із зображеннями.

Цікаві завдання на двовимірні та тривимірні масиви

Ви досить знаєте про багатовимірні масиви в Java і, якщо відчуваєте в собі сабо, можете спробувати вирішити якесь із завдань нижче. Вони непрості, але цікаві. Хрестики нолики. Введіть поле 3х3, створіть двох гравців, які ходять по черзі. Спочатку поле порожнє, і кожне з порожніх полів перший гравець може ставити хрестик, а другий нолик. Виграє той, хто першим збере три хрестики або три нулики, розташовані в один рядок, один стовпець або по діагоналі. Мураха Ленгтона . Є поле, розбите на клітини (двовимірний масив), пофарбовані в чорний або білий колір (можна задати випадковою функцією). В одній із клітин випадковим чином матеріалізується “мураха”, яка на кожному кроці може пересуватися в одному з чотирьох напрямків на сусідню клітину по горизонталі чи вертикалі. Правила пересування мурахи:
  • На чорній клітині мурашка повинна повернути на 90° вліво, змінити колір своєї клітини на білий, потім зробити крок уперед на наступну клітину.
  • На білій клітині мурашка повертається на 90° праворуч і змінює колір своєї клітини на чорний, потім робить крок уперед наступну клітину.
Напишіть метод, який прораховує ітерацію на кроці номера nпри заданій початковій позиції мурашки. Поле можна заповнити випадковим чином нулями і одиницями (або позначити їх літерами Wі Bяк ми робабо в прикладі про шахівницю). Також потрібні ще два параметри - горизонтальна і вертикальна позиція мурахи, а також його напрямок на цьому кроці (північ, південь, захід, схід), при цьому за умовчанням мураха дивиться на північ. Кубик Рубіка можна спробувати змоделювати за допомогою тривимірних масивів. Стандартний кубик Рубика має 6 граней, і кожна з них є тривимірним масивом кольорових квадратів Color[][][] rubik = new Color[6][3][3]. Однак реалізація кубика Рубіка – завдання нетривіальне.

Корисні матеріали про масиви

Масивам (переважно одномірним, оскільки вони набагато частіше застосовуються на практиці) присвячено багато статей на JavaRush. Зверніть на них увагу.
  1. Масиви в Java - про масиви для новачків з прикладами
  2. Щось про масиви — хороша докладна стаття про масиви
  3. Клас Arrays та його використання - у статті описані деякі методи класуArray
  4. Масиви – перша лекція JavaRush, присвячена масивам.
  5. Повертайте масив нульової довжини, а не null - автор "Ефективного програмування" Джошуа Блох розповідає про те, як краще повертати порожні масиви
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ