JavaRush /Курсы /Java Syntax New Beta /Двумерные массивы

Двумерные массивы

Java Syntax New Beta
6 уровень , 5 лекция
Открыта

Фрагмент лекции JavaRush - университета.


— Приветствую, Амиго!

— Здравствуй, Риша!

— Ты уже знаешь кое-что о массивах, даже задачи уже успел порешать, я надеюсь. Но ты знаешь далеко не всё. Вот например, ещё один интересный факт о массивах. Они — массивы — бывают не только одномерными (линейными), но и двумерными.

— Эмм… И что это значит?

— А это значит, что ячейки массива можно представить не только в виде столбца (или строки), но и в виде прямоугольной таблицы.

int[][]имя = new int[ширина][высота];

— Где имя — это имя переменной-массива, ширина — это ширина таблицы (в ячейках), а высота — это высота таблицы. Посмотри на пример:

int[][] data = new int[2][5];
data[1][1] = 5;
Создаем двумерный массив: два столбца и 5 строк.
В ячейку (1,1) записываем 5.

— Вот как это будет выглядеть в памяти:

— Кстати, для двумерных массивов можно тоже использовать быструю инициализацию:

// длины месяцев года поквартально
int[][] months = { {31, 28, 31}, {30, 31, 30}, {31, 31, 30}, {31, 30, 31} };

— Хм… интересно получается. Если представить что в первых внутренних скобках один элемент, в следующих второй… Выходит, двумерный массив — это как бы массив массивов?

— Какой же ты смышлёный ученик! Именно так. Первый его элемент — одномерный массив {31, 28, 31}, второй — {30, 31, 30}, и так далее. Но к этому мы вернёмся чуть позднее в этой лекции. А пока постарайся представить двумерный массив в виде таблицы со строками и столбцами, которые образуют ячейки на пересечении.

— Представил. Кстати, а для чего их вообще используют, эти двумерные массивы?

— Программисту часто может понадобиться двумерный массив. Если присмотреться, реализация практически любой настольной игры — это же готовый двумерный массив: «Шахматы», «Шашки», «Крестики-Нолики», «Морской бой»:

— Я понял! Игровое поле «Шахмат» или «Морского боя» просто идеально ложится на двумерные массивы!

— Да, только в качестве координат клеток нужно будет использовать только числа. Не «пешка e2 -> e4», а «пешка (4,1) -> (4,3)». Тебе как программисту будет даже проще.

Расположение элементов в массивах: (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 столбцов.

— Теперь вижу. 2 — это высота, и 5 — ширина… И как же тогда поступать?

— Тебе решать, как удобнее. Главное, чтобы все программисты, работающие над одним проектом, придерживались одного подхода.

— Если ты будешь работать над проектом, где много инициализированных двумерных массивов в коде, то скорее всего там все будут отталкиваться от быстрой инициализации данных и будет стандарт «высота»-«ширина».

— Если же ты попадешь в проект, где много математики и работают с координатами (например, работа с игровыми движками), там скорее всего будут придерживаться подхода «ширина»-«высота».

Устройство двумерных массивов

— Итак, ты помнишь, какую особенность структуры двумерных массивов ты подметил в начале лекции?

— Да, то, что двумерные массивы — это на самом деле массивы массивов!

— Совершенно верно. Другими словами, если в случае с обычным массивом «переменная-массив хранит ссылку на контейнер, который хранит элементы массива», то в случае с двумерными массивами у нас ситуация немного взрывоопаснее: переменная-двумерный-массив хранит ссылку на контейнер, который хранит ссылки на одномерные массивы. Это лучше один раз увидеть, чем сто раз попробовать объяснить:

Слева у нас «переменная-двумерный-массив», которая хранит ссылку на «объект-двумерный-массив». В середине — «объект двумерный массив», в ячейках которого хранятся ссылки на одномерные массивы — строки двумерного массива. Ну и справа ты можешь видеть четыре одномерных массива — строки нашего двумерного массива. Это то, как на самом деле устроены двумерные массивы.

— Здорово! Но что нам это даёт?

— Поскольку «контейнер контейнеров» хранит ссылки на «массивы-строки», мы можем очень быстро и просто менять строки местами. Чтобы получить доступ к «контейнеру контейнеров», нужно просто указать один индекс вместо двух. Пример:

int[][] data = new int[2][5];
int[] row1 = data[0];
int[] row2 = data[1];

— Посмотри на код ниже. С его помощью мы можем поменять строки местами:

// Важная матрица с данными
int[][] matrix = {
  {1, 2, 3, 4, 5},
  {5, 4, 3, 2, 1}
};

int[] tmp = matrix[0];
matrix[0] = matrix[1];
matrix[1] = tmp;
Двумерный массив





В matrix[0] у нас хранится ссылка на первую строку.
Меняем ссылки местами.

В итоге массив matrix выглядит так:
{
  {5, 4, 3, 2, 1},
  {1, 2, 3, 4, 5}
};

— Понял. Работает как обычный swap двух элементов.

— Так и есть. Ну а если ты обращаешься к ячейке двумерного массива, но после имени массива указываешь только один индекс, ты таким образом обратишься к контейнеру контейнеров, в ячейках которого хранятся ссылки на обычные одномерные массивы.

— Всё кажется логичным и понятным. Спасибо за лекцию, Риша!

— Пожалуйста. Применяй на практике с умом.

6
Задача
Java Syntax Pro, 6 уровень, 5 лекция
Недоступна
Таблица умножения
Проинициализируй массив MULTIPLICATION_TABLE значением new int[10][10], заполни его таблицей умножения и выведи в консоли в следующем виде: 1 2 3 4 … 2 4 6 8 … 3 6 9 12 … 4 8 12 16 … … Числа в строке разделены пробелом.
Комментарии (88)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
MYVas Уровень 10
21 декабря 2024
мучался и всё таки решил третью задачу с использованием if и && и ||. Несмотря на то что правильное решение отличается от моего, но мой вариант также прошел проверку
ELT_On1x Уровень 9
15 августа 2023
Абсолютно не понятно почему: for (int j = 1; j < chars.length + 1; j++) { for (int i = 1; i < chars.length - 1; i++) { chars[i][j] = '-'; } } не является верным? (((
Cat_Virus Уровень 9
30 декабря 2023
Если попробовать изменить количество строк или столбцов в массиве, то это решение уже становиться не верным. С другой стороны, я вообще указал вместо chars.length конкретные значения 3 и 5, и мне ответ засчитался как правильный. Правда, я циклы вкладывал в "нормальном" порядке.
Виталий В. Уровень 7
17 июля 2024
Я также решил эту задачу и ее приняли, но в вашем коде есть ошибка

for (int j = 1; j < chars.length + 1; j++) { 
должно быть

for (int j = 1; j < chars.length - 1; j++) { 
И да, код работает для любого количества строк/столбцов
14 июня 2023
А ведь вы можете отсечь первый-последний столбец и первый-последний символ строки просто условием в цикле, то есть начинать его не с нуля, а с 1 и заканчивать не длиной, а длиной минус 1. В таком случае код выглядит намного проще.
Греча Уровень 19
6 мая 2023
все вроде сам понял)
Vladimir Уровень 21
13 апреля 2023
Админы, решил обратить ваше внимание. В некоторых уроках, как и в этом, аватарка персонажа (Диего) не совпадает с текстом ("— Здравствуй, Риша!"). Баг или фича?)
Вячеслав Уровень 6
20 марта 2023
Вообще ничего не понимаю
MaximusLiter Уровень 6
23 апреля 2023
держись ты не один))
Sotonu Уровень 24
16 февраля 2023
Объясните мне пожалуйста, как решить ошибку. "Таблица умножения" int[][] MULTIPLICATION_TABLE = new int[10][10]; for(int i=0;i<=9;i++){ for(int j=0;j<=9;j++){ MULTIPLICATION_TABLE[i][j] = (i+1)*(j+1); System.out.print(MULTIPLICATION_TABLE[i][j] + " " ); } System.out.println(""); }
Владислав Уровень 16
23 февраля 2023
попробуйте ковычки эти "" убрать в скобках () на предпоследней строчке кода.
Shubino_09 Уровень 6
27 февраля 2023
MULTIPLICATION_TABLE[i][j] = (i+1)*(j+1); Добрый день, я вот у вас эту строчку взял, вставил в свой код, и все сработало моментально, как бы все выполнилось, а как это работает не понимаю, есть какой нибудь материал почитать по теме этой строки? Что бы понимать как работает. Как вот указывается два индекса, после какое то перемноженное действие. Вроде как то поверхностно понятно, но вот сам сейчас заново это написать не смогу....
Sotonu Уровень 24
16 февраля 2023
Я скоро заплачу от беспомощности
FelixDS Уровень 11
9 января 2023
Чет с массивами прям беда какая-то (
Ekaterina K Уровень 7
10 января 2023
У меня тоже... надеюсь, дальше оклемаюсь))))
Anonymous #3221386 Уровень 1
8 января 2023
😇