Перед тем как я перейду к многомерным массивам, я хочу рассмотреть пару выражений, которые могут быть полезны для циклов и массивов.
Это выражения break и continue.
Помните ли вы, где мы уже видели выражение break? Это было в выражении switch.
Когда break используется в выражении switch, выполнение кода прерывается.
Выражение break может также использоваться в любом типе цикла.
Когда break выражение встречается в цикле, выполнение цикла завершается.
Я приведу соответствующий пример позже.
В случае continue выражения, когда оно встречается в цикле, оставшийся код тела цикла пропускается и начинается новая итерация цикла.
Одно важное различие между выражениями break и continue состоит в том, что continue выражение не завершает выполнение цикла, а вместо этого только пропускает оставшийся код действия цикла и код продолжается со следующей итерации.
Давайте рассмотрим пару примеров.
В этом примере, в дополнении к иллюстрации использования break выражения, также показана важная операция, которая часто используется в компьютерных приложениях.
Сегмент программы здесь ищет определенный элемент в массиве.
Я уверен, что все вы искали какую-либо информацию в Интернете, используя поисковые машины, например, Google.
Вместо выполнения сложного поиска, программа здесь просто пытается искать определенное значение в данном массиве.
Программа начинается с инициализации целого массива, состоящего из 5 элементов.
Целая переменная value затем устанавливается в значение, для которого будет выполняться поиск.
Размер устанавливается как длина массива intArray, используя переменную экземпляра length.
Логическая переменная found используется, чтобы отслеживать, найдено ли значение.
В начале эта переменная устанавливается как false, потому что значение еще не найдено в самом начале.
Затем объявляется переменная i, которая используется как индекс для цикла.
Возникает вопрос, почему она не объявлена внутри цикла.
Вы видите здесь, что индекс, также, используется для отслеживания позиции значения в массиве, если оно будет найдено.
Если индекс объявить внутри цикла for, его область видимости будет ограничена циклом for, и соответственно, значение индекса не будет доступно вне цикла.
Цикл здесь анализирует каждый элемент в массиве один за другим, проверяя соответствует ли его значение искомому значению.
Если соответствие найдено, логическая переменная found будет установлена как true.
И выражение break завершит выполнение цикла.
Далее будет выполнено следующее выражение после цикла.
В этом случае выражение if-else проверит, равна ли переменная found значению true.
Тогда индекс i или позиция найденного значения в массиве будет выведена пользователю.
Как я уже говорил ранее, если переменная i будет объявлена внутри цикла for как индекс, она не будет доступна здесь, вне цикла for.
Выражение else выводит сообщение, что значение не найдено.
Заметьте, что метод находит только первое вхождение значения.
Поэтому, даже если значение встречается в массиве несколько раз, будет использоваться только первый индекс.
Вы найдете, что даже если выражение break удалить, программа все равно будет находить значение, однако использование выражения break может экономить вычислительное время для больших массивов.
Теперь этот пример показывает использование выражения continue, и считает число вхождений искомого значения в массиве.
Массив здесь инициализируется так же, как и в предыдущем примере.
Искомое значение устанавливается как 90.
Здесь также есть одна дополнительная переменная nTimes, которая дает число вхождения значения.
Заметьте, что переменная i здесь используется только как индекс цикла, поэтому здесь не важно, где эта переменная будет объявлена, внутри цикла или вне цикла.
Цикл здесь анализирует элементы массива один за другим.
Внутри цикла, если элемент не равен искомому значению, выражение continue выполняется и пропускает окончание цикла, в отличие от выражения break, которое завершает цикл.
Далее начинается новая итерация и продолжается анализ следующего элемента массива.
Если же элемент равен искомому значению, переменная nTimes увеличится на 1.
Можно также увидеть, что такой же результат может быть получен без использования выражения continue, например, используя выражение if-else.
Но в некоторых приложениях выражение continue может существенно упростить код.
Когда цикл завершается, будет выведено число вхождений искомого значения.
Два метода поиска, которые мы только что рассмотрели, анализируют элементы массива один за другим, и такой подход называется линейным поиском.
Однако существуют и более эффективные алгоритмы, по сравнению с линейным поиском, особенно если элементы сортируются.
Я вернусь к этой теме позже.
Идея одномерного массива может быть легко расширена до двумерного массива, или массива даже более высокой размерности.
Способ, с помощью которого реализуются многомерные массивы, это рассматривать двумерный массив как массив одномерных массивов, 3D массив в виде массива 2D массивов и так далее.
Сначала сосредоточимся на двумерных массивах.
Итак, в 2D массиве у вас есть массив 1D массивов, то есть, для каждого элемента массива, вместо того чтобы держать данные определенного типа, каждый элемент массива представляет собой одномерный массив.
Я буду использовать схему для дополнительной иллюстрации, что это значит, позже.
В общем, двумерный массив имеет определенное количество строк, давайте назовем это число R, и определенное количество столбцов C, при этом R и C не обязательно должны быть одинаковыми.
Для тех, кто изучал матрицу линейной алгебры, 2D массив похож на 2D матрицу, а 1D массив, как вектор.
Но не беспокойтесь об этом, если вы не изучали матрицы раньше, потому что вам не нужно это для понимания массива.
В повседневной жизни, многие приложения требуют обработки многомерных данных.
Например, вы можете использовать 2D массив, чтобы представлять разные оценки, в том числе оценки за экзамены, оценки за домашние задания, оценки за лабораторные работы и окончательную оценку для каждого студента на курсе.
В таком представлении, каждая строка массива может представлять различные оценки, полученные студентом, и каждый столбец представляет собой различные виды оценки, скажем, столбец один для оценок за экзамены, столбец 2 для оценок за домашние работы, и так далее.
В частности, оценки всех студенты, полученные за различные работы на курсе, могут быть представлены в виде 2D массива, и для тысяч студентов, это был бы очень большой массив.
Результаты матчей в различных видах спорта также могут быть представлены в виде 2D таблиц или массивов.
Вот результаты матчей кубка мира в разных группах.
Каждая строка представляет результаты для разных команд и каждый столбец для различных атрибутов.
Коллекция из этих таблиц может быть представлена в виде 3D массива.
Я уверен, что вы можете придумать много других примеров.
Давайте, используем результаты тестов студентов в качестве примера для дальнейшего объяснения идеи 2D массивов.
Когда мы обсуждали 1D массив ранее, мы использовали массив оценок для хранения оценок для группы студентов.
Когда каждый студент берет несколько тестов, предполагая, что есть только четыре студента, и каждый студент взял 4 теста, результаты могут быть представлены массивом 4х4, как этот, где каждая строка представляет результаты тестов для каждого студента, а каждый столбец представляет результаты, полученные различными студентами в том же тесте.
Массив не обязательно должен быть квадратным, так как, как правило, гораздо больше студентов, чем число тестов.
Обратите внимание, что так же, как в одномерном массиве, индексы для студентов и номеров тестов начинаются с 0.
Это синтаксис объявления 2D массива.
Далее этот вопрос будет обсуждаться более подробно.
Здесь я буду использовать класс оценок, чтобы проиллюстрировать различные аспекты 2D массивов, в том числе объявление и инициализацию, а также доступ и перемещение отдельных элементов 2D массивов с помощью вложенных циклов.
Здесь показан синтаксис объявления 2D массива оценок типа double как переменной экземпляра для класса оценок.
Подобно одномерному массиву, это объявление должно указать тип данных, которые будут храниться в массиве.
Независимо от того, какая используется размерность, массивы являются однородными по типам, то есть, содержат данные одного и того же типа.
Отличие здесь в том, что есть две пары квадратных скобок для указания размера 2D массива, по одной для каждого из 2-х измерений.
Объявление, подобно этому, просто определяет ссылочную переменную для массива, но при этом память не была еще выделена для элементов массива.
Чтобы инициализировать массив, давайте напишем метод с названием initializeAllScores.
Также как мы делали в одномерном массиве, двумерный массив создается с помощью оператора new с последующим указанием типа данных, а затем указания размера каждого из измерений для 2D массива.
Это объявление выделит достаточно памяти для хранения всех элементов создаваемого массива.
Как упоминалось ранее, Java автоматически инициализирует каждый элемент массива на значение по умолчанию для соответствующего типа.
В этом случае, 0.0 используется в качестве значения по умолчанию для типа double.
Я хочу отметить, также, что, как только массив создан, размер массива является фиксированным и не может быть изменен позже в программе.
Здесь я хочу дать вам некоторую концептуальную идею о том, как этот двумерный массив представлен.
Когда делается объявление, создается ссылочная переменная scores.
Когда оператор new используется для создания массива, первое измерение, указанное здесь, создаст одномерный массив из 4 элементов.
И каждый элемент этого одномерного массива также ссылочная переменная, указывающая на другой одномерный массив.
В этом примере элементы в одномерных массивах синего цвета имеют тип double.
В общем, каждый элемент массива можно использовать для более сложных объектов до тех пор, пока они одного и того же типа.
После того, как объявлен массив, также, как и для одномерного массива, можно использовать операторы присваивания, чтобы фактически инициализировать массив.
Отличие здесь в том, что индексы для 2D массива указаны в двух парах квадратных скобок, где первый индекс – это индекс строки и второй это индекс столбца.
В операторах присваивания первый индекс, 0, массива относится к первой строке массива.
Таким образом, расположение с индексами 0,0 дает значение 99.
Расположение 0,1 дает значение 89.
Расположение 0,2 дает значение 85.
Последний элемент этой строки, с индексами 0,3 дает 92.
На второй строке, первый индекс равен 1, а 2-й индекс меняется от 0 до 3.
На 3-й строке, первый индекс 2.
Для последней строки, 4-й, обратите внимание, что индекс строки 3, что на единицу меньше, чем размер строки.
И последний элемент в этом 2D массиве индексируются как 3,3.
Подобно одномерному массиву, еще один способ инициализации двумерного массива – это сделать объявление и инициализацию в одном выражении, задав начальные значения в паре фигурных скобок.
В случае двумерного массива, значения для каждой строки указываются в отдельном списке в фигурных скобках, то есть, в виде одномерного массива.
Эта инициализация также определяет размер массива 4 на 4.
Подобно одномерному массиву, этот формат инициализации должен быть сделан в то же время, когда производится объявление массива.
Компилятор даст вам ошибку, если это делается в отдельном выражении, после того как был объявлен массив.
3-й шаг в определении класса оценок это определение метода с названием getScoreByIndices для доступа к элементам в 2D массиве.
Этот метод принимает два параметра, которые определяют индексы строки и столбца элемента, чтобы быть найденным, и возвращает значение типа double потому, что это тип данных, хранящихся в массиве.
Внутри метода, мы должны сначала узнать размер массива.
В случае одномерного массива, можно получить размер массива с помощью переменной экземпляра length.
Помните, что length является переменной экземпляра, а не методом, поэтому не содержит пару скобок после length.
В случае двумерного массива, его размер определяется количеством строк, а также числом столбцов.
Так как же нам определить количество строк и количество столбцов?
Два выражения здесь выполнять эту работу.
Давайте использовать схему, чтобы проиллюстрировать, как это работает.
Помните, что scores на самом деле является одномерным массивом с 4-я элементами, а каждый из его элементов является другим массивом.
Таким образом, чтобы определить размер первого индекса, или количество строк, вы можете использовать scores.length.
В этом примере, scores.length даст значение 4, поскольку scores является массивом с 4-я элементами.
Теперь, что насчет количества столбцов?
Как вы можете видеть, каждый элемент scores, "scores [0]", "scores [1]" и так далее это одномерные массивы.
Таким образом, чтобы определить размеры этих массивов, можно использовать scores[0].length для первой строки, scores[1].length для 2-й строки и так далее.
В этом примере, все они дают то же значение 4, то есть количество столбцов.
Так что первое выражение определяет количество строк, а затем присваивает переменной numOfRows, и второе выражение – число столбцов и присваивает переменной numOfCols.
В Java, вы на самом деле можете определить 2D массив с различным числом столбцов для разных строк, но в этом примере, будем считать, что все строки имеют одинаковое число столбцов, так что вы можете использовать scores с индексом 0 или любой другой индекс для определения количества столбцов.
Теперь, когда у нас есть размер 2D массива, мы можем проверить, находятся ли индексы, определяемые в качестве параметров, в пределах диапазона.
Первое if выражение проверяет, находится ли индекс строки в пределах диапазона для числа строк.
Обратите внимание, что первое условие проверяет, является ли индекс точно меньше 0, так как 0 является допустимым индексом, и второе условие, чтобы проверить, является ли индекс больше или равен numOfRows, так как даже равно numOfRows недопустимо, потому что размер на единицу меньше, чем число строк.
И второе if выражение проверяет индекс столбца.
Значение -1 возвращается, если любой из индексов вне диапазона, предполагая, что все значения в массиве неотрицательны.
Если индекс строки и индекс столбца в пределах диапазона, значения scores, индексируемые индексом строки и индексом столбца, будут возвращены в результате методом getScoresByIndices.
Последняя часть определения scores это печать отдельных элементов в массиве scores путем обхода 2D массива, используя метод printAllScores.
Первые шаги в printAllScores это получить количество строк и количество столбцов из массива, аналогично тому, что мы сделали в предыдущем методе.
Это полная реализация метода.
Обратите внимание, что здесь есть два for цикла, или два вложенных цикла, один для управления индексом строки r и другой для индекса столбца c.
Использование вложенных циклов является довольно распространенным в обходе многомерных массивов.
Когда выполнение начинается с внешнего цикла, индекс строки r установлен в 0, и выражение IO.output распечатает номер строки в консоли.
Когда внутренний цикл выполняется, индекс столбца с будет установлен в 0.
Внутри второго for цикла, элемент массива с индексом 0, 0 будет найден с помощью метода getScoreByIndices, который мы только что описали, и значение 99 будет получено и выведено на консоль.
Выполнение внутреннего цикла будет продолжаться за счет увеличения С на 1, элемент с индексом 0,1 затем будет извлечен и выведен.
Этот процесс будет повторяться, пока С не станет равным 3.
И цикл завершится, когда С становится равным 4.
Оператор оutputln во внутреннем цикле будет помещать строку вывода на новой линии.
Когда выполнение перейдет к началу внешнего цикла, г будет увеличен на 1, а элементы из второй строки будут получены один за другим с помощью внутреннего цикла.
Этот процесс будет продолжаться, пока последний элемент массива с индексом 3,3 не будет достигнут.
Опять же, я хочу отметить, что последний элемент этого массива индексируются как 3,3, хотя размер массива составляет 4 на 4, потому что индексы начинаются с 0.