T.M. SoftStudio

feci quod potui, faciant meliora potentes

Купить полную версию курса "Введение в вычисления с Java" (русскоязычная версия, лекции, тесты, лабораторные работы)

Введение в вычисления с Java. Массивы, простая сортировка, многомерные массивы

Неделя 6

Лекция 27

Массивы

Мы обсуждали различные структуры управления последнее время.

И я хочу обратить ваше внимание опять на то, что отступы кода игнорируются в Java, и ключевое слово else соотносится с ближайшим if.

Если вы хотите соотнести else с другим if, вы должны использовать фигурные скобки.

Использование фигурных скобок также улучшает читаемость кода.

Однако другие языки программирования могут следовать другому синтаксису, например, в языке Python отступы кода могут использоваться для связывания if и else.

Давайте теперь обсудим новую тему массивы.

Циклы используются часто вместе с массивами.

Во-первых, давайте поговорим о том, почему нам нужны массивы.

До этого, мы использовали переменные, которые представляли только один объект данных.

Поэтому каждое имя, которое мы использовали, могло представлять только одну порцию примитивных данных или один экземпляр объекта.

Хотя у объекта могло быть несколько полей, вам нужно было давать различным экземплярам объектов различные имена.

При этом возникают трудности, когда вы имеете большое число объектов одного типа.

Например, когда вы имеете большое число студентов, скажем 100 студентов в классе, вы должны создать имена переменных Score1, Score2, Score3, и так далее до Score100, для хранения экзаменационных оценок каждого студента.

Сделайте объявление 100 различных переменных и представьте, что если вам нужно сделать что-нибудь с оценками, скажем, добавить бонус к каждой оценке, вам нужно будет написать 100 выражений в форме Score1=Score1 + 1, Score2 =Score2 + 1, и так далее.

Даже если вы используете оператор инкремента, вы все равно должны написать Score1++, Score2++, и до Score100++.

И нет таких программистов, которые бы желали выполнять такую утомительную работу.

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

Использование массива упрощает выполнение таких утомительных задач, как, например, определение средней оценки, максимальной и минимальной оценки, вывод списка оценок, сортировка списка, когда список имен выстраивается в алфавитном порядке.

В реальной жизни иногда вам нужно обрабатывать даже многомерные данные, например, работать с 2-х мерными цифровыми изображениями. И вы найдете, что массивы будут полезны для таких приложений.

Массив это коллекция однородных объектов данных, при этом данные должны быть одного типа.

Синтаксис объявления массива это, во-первых, определить тип данных, затем идут квадратные скобки.

Тип данных это тип данных, которые должны храниться в массиве.

Это может быть примитивный тип данных, int, double, или пользовательский тип, класс, как мы рассматривали раньше, courseGrade или Сar.

Помним, что здесь используются квадратные скобки, а не круглые или фигурные скобки.

Имя массива, как и имя переменной, может быть любым действительным именем для переменной.

Здесь примеры оформления массивов.

Первый пример, это объявление массива double типа с именем testScores.

Второй пример, это массив целых чисел с именем studentID.

И последний пример, это double массив с именем stockIndex.

Эти объявления в реале не создают массив.

Они только создают ссылочную переменную массива.

Для того чтобы реально создать массив, вы можете использовать оператор new и определить размер массива в квадратных скобах, который вы хотите создать.

И в этом случае вы создаете массив с именем testScores, типа double, с 100 элементами.

Во втором примере создается массив studentID типа int, с 50 элементами.

Последний пример немного отличается.

В нем объявляется и сразу создается массив в одном выражении.

В этом выражении создается массив с именем stockIndex, типа double, с 365 элементами.

Нужно отметить, что размер массива не может быть отрицательным.

Java позволяет создавать массивы с нулевым размером, но такой пустой массив не может что-либо хранить.

Java также позволяет объявлять массивы, создавать их и инициализировать в одном выражении.

В этом примере массив с именем testScore, типа double, создается.

Четыре числа внутри фигурных скобок затем используются для инициализации четырех элементов массива.

Результат проиллюстрирован диаграммой.

Заметьте, что размер testScore определяется, когда массив создается, используя 4 числа при инициализации.

Я хочу указать, что такая короткая инициализация должна быть сделана в одном выражении.

Например, если массив уже объявлен, вы не можете инициализировать массив с помощью списка начальных значений в фигурных скобках.

Java выдаст вам ошибку в этом случае.

Java инициализирует элементы массива в их значения по умолчанию.

Но хорошая практика программирования не полагаться на это.

Отдельные элементы массива могут быть доступны с помощью индекса.

Рассматривая последний пример, действительные индексы находятся в диапазоне от 0 до 3 для массива размером 4.

Важно помнить, что индекс массива начинается с 0, а не с 1.

Общая ошибка, индексировать первый элемент, используя 1, вместо 0.

Поэтому, действительные индексы в этом примере 0, 1, 2, 3.

Сослаться на отдельный элемент массива можно, указав имя массива, а затем индекс в квадратных скобках.

В этом примере первый элемент testScore с 0 индексом имеет значение 100.

testScore[1] даст значение 90.

testScore[2] имеет значение 85.

Последний элемент массива с индексом 3 имеет значение 72.

В этом примере класс Scores определяется.

Внутри класса переменная экземпляра scoreArray double типа объявляется, но еще не создается.

Конструктор определяется с 1 параметром, который дает размер массива.

Надо заметить, что в Java размер массива может быть динамически определен.

Когда конструктор вызывается, массив создается.

Предположим, размер имеет значение 4, и диаграмма здесь иллюстрирует создание массива.

Ссылочная переменная scoreArray даст адрес памяти, где первый элемент массива scoreArray расположен.

Как я упомянул, Java будет инициализировать элементы массива значениями по умолчанию.

В случае целых чисел, эти значения будут 0.

Но рекомендовано самостоятельно инициализировать массив перед его использованием.

Заметьте, что первый элемент массива имеет индекс 0, а последний индекс 3, который меньше чем размер массива.

Примеры

Давайте посмотрим на метод setScore, который работает с массивом scoreArray, который мы только что создали.

Метод setScore спрашивает пользователя ввести оценки, одну за другой, в соответствующие элементы массива.

Перед тем как начать ввод, мы должны определить количество элементов массива.

В Java размер массива может быть получен из финальной переменной экземпляра с именем length.

Поэтому, поместив имя массива, в этом случае, scoreArray, перед .length это даст нам размер массива scoreArray.

Помним, что размер массива на единицу больше, чем максимальный индекс массива.

Цикл for внутри метода в первую очередь инициализирует счетчик-переменную i в 0.

При этом, ссылаясь на первый элемент массива scoreArray, внутри цикла, пользователь будет приглашен для ввода.

Если пользователь введет 100 как оценку, IO.inputDouble возьмет введенное значение и присвоит его элементу массива с индексом 0, который является первым элементом.

Индекс и позиция в массиве отличаются, но мы должны принять это.

Когда действие внутри тела цикла for завершится, счетчик i увеличится на 1.

Пользователь введет другую оценку, скажем 90, которая присвоится индексу 1 массива.

Далее процесс продолжится и i++ увеличит i до 2.

Следующее введенное значение, скажем 80, будет присвоено третьему элементу массива.

Выражение i++ затем увеличит i до 3 и последний элемент массива примет значение 70.

Когда условие цикла будет проверено снова, i++ даст значение 4, которое будет больше, чем размер массива, и цикл будет завершен.

Метод getScore будет возвращать значение элемента массива, который имеет индекс, указанный параметром метода.

Это может быть достигнуто, используя простое if-else выражение, где мы делаем первую проверку индекса в диапазоне.

Помним, что действительный диапазон индексов от 0 до размера массива минус 1.

Первое условие здесь проверяет индекс больше или равен 0, и второе условие проверяет индекс меньше чем размер массива, который дается переменной экземпляра length.

Второе условие строго меньше, потому что максимальный индекс это размер массива минус 1.

Если оба условия возвращают true, getScore возвратит значение, хранимое в индексе массива.

Например, если индекс 1, второй элемент scoreArray будет возвращен.

Если одно из условий возвращает false, условное выражение возвратит false и выражение else будет выполнено.

Сообщение об ошибке будет выведено на экран и значение -1 будет возвращено.

Возвращаемое значение здесь ничего не означает, но что-то должно быть возвращено, потому что getScore метод определен как возвращающий значение типа double.

Так как значения хранятся в массиве, мы можем выполнять различные операции над массивом, перемещаясь по массиву один элемент за другим.

Следующий метод, который я собираюсь обсудить здесь aveScore, вычисляет среднее всех значений, хранимых в массиве.

Предположим, массив обеспечивается переменной экземпляра, в противном случае, мы можем передать массив в метод как параметр.

Я вернусь к этому позже.

Метод начинается с определения двух переменных.

Одна переменная типа double для хранения суммы всех значений массива и вторая для размера массива, который может быть определен из переменной экземпляра length.

Главная часть программы обновляет общую сумму, добавляя значение каждого элемента массива, один за другим, используя цикл for.

Мы уже видели подобный цикл for в методе setScore, так что это общий подход для перебора элементов массива фиксированной длины.

Помним снова, что индекс начинается с 0 и меньше чем размер массива.

Последнее выражение метода aveScore делит общую сумму на размер, что даст среднее всех оценок, и среднее затем будет возвращено как результат.

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

Этот метод maxIndex, который вместо нахождения максимального значения, находит позицию или индекс элемента массива, который дает максимальное значение.

Метод maxIndex имеет один параметр, это размер целого типа, и возвращает целое значение, которое дает индекс максимального элемента.

Вы может быть удивлены, почему мы определяем размер как параметр, а не используем переменную экземпляра length для определения размера массива.

Это делает метод более гибким, так как в некоторых приложениях вы, может быть, захотите обработать только часть массива, вместо перебора всего массива.

Я дам вам больше примеров использования этой опции позже.

Наш метод объявляет локальную переменную mIndex, для хранения позиции максимального элемента.

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

Если размер будет слишком большим, мы его сбросим до реального размера.

Цикл for будет проверять элементы массива, один за другим, до индекса равного размеру минус 1, и будет проверять текущий элемент массива больше чем текущий максимум.

Заметьте, что текущий максимум получается с помощью переменной mIndex, потому что это позиция найденного максимума.

Если условие верно, новый максимум найден и переменную mIndex нужно обновить в текущий индекс.

Когда цикл for завершится, mIndex будет содержать позицию максимального элемента массива и его значение будет возвращено как результат.

Вы можете подумать о том, что произойдет, если максимальное значение встретится несколько раз в массиве.