Почему поиск максимального значения в массиве происходит неверно: вместо 10 выводится 7?
Задача следующая:
Пользователь вводит значение в массив и исходя из его значений выводится максимальное значение:
Мой код:
public class max_number{
public static void main(String[] args) {
int[] a;
int n;
int max3 = arr[0];
Scanner in = new Scanner(System.in);
System.out.println("Сколько будет значений?");
n = in.nextInt();
a = new int[n];
for (int i = 0; i <n; i++){
System.out.println("Выведи значение для" + i + ": ");
a[i] = in.nextInt();
if (arr[i] > max3){
max3 = arr[i];
}
}
System.out.println(max3);
}
}
Фактический результат сейчас:
Пользователь указывает, что в массиве будет 3 значения: 5, 7, 10.
Максимальное значение сейчас выводит 7, а ожидаемое - 10:
Ответы (3 шт):
Ну начнём с того, что у вас переменная называется то arr, то a... Буд то не вы вовсе код писали)
Да и запустить его не получится
Заметим, что вы выполняете
int max3 = arr[0];
ещё до того, как arr был проинициализирован. Перенесём эту строку ниже
Вот что получается:
public class max_number {
public static void main(String[] args) {
int[] arr;
int n;
Scanner in = new Scanner(System.in);
System.out.println("Сколько будет значений?");
n = in.nextInt();
arr = new int[n];
int max3 = arr[0];
for (int i = 0; i < n; i++){
System.out.println("Выведи значение для" + i + ": ");
arr[i] = in.nextInt();
if (arr[i] > max3){
max3 = arr[i];
}
}
System.out.println(max3);
}
}
После небольшого изучения кода заметим, что массив используется только для хранения текущего значения, а значит мы его можно просто поменять на обычную переменную
Предполагаю что изначально был запланирован следующий алгоритм:
- Создаём массив длины
n - Проходимся по каждому элементу массива и вписывает в него введённое пользователем значение
- Проходимся по каждому элемент массива и ищем наибольшее
- Выводим его
В данном контексте массив будет полезнее, так как в будущем мы сможем передавать любой массив.
Однако в данном конкретном случае он вообще никак не используется, и по сути алгоритм такой:
- Проходимся в массиве от
0доn- Запрашиваем число от пользователя
- Если число больше текущего максимального, то меняем максимальное на текущее
- Выводим результат
Как мы видим массив нам и не нужен, и код легко можно переписать на такой:
public class max_number {
public static void main(String[] args) {
int[] arr;
Scanner in = new Scanner(System.in);
System.out.println("Сколько будет значений?");
int n = in.nextInt();
int max = 0;
for (int i = 0; i < n; i++){
System.out.println("Выведи значение для " + i + ": ");
int currentValue = in.nextInt();
if (currentValue > max){
max = currentValue;
}
}
System.out.println(max);
}
}
Данный код успешно работает с положительными числами. Однако если мы введём отрицательное, то максимальное будет равно нулю. Есть простых способа решить эту проблему:
- Задать
minна минимальное допустимое число для типаint - Задавать
minпервым введённым числом
Мы будем решать через второй вариант. Вынесем первую итерацию цикла из цикла:
System.out.println("Выведи значение для " + 0 + ": ");
int max = in.nextInt();
И следовательно уберём первую итерацию из самого цикла:
for (int i = 1; i < n; i++) {...}
Финальный код:
public class max_number {
public static void main(String[] args) {
int[] arr;
Scanner in = new Scanner(System.in);
System.out.println("Сколько будет значений?");
int n = in.nextInt();
// Итерация 0:
System.out.println("Выведи значение для " + 0 + ": ");
int max = in.nextInt();
// Итерации 1..n:
for (int i = 1; i < n; i++){
System.out.println("Выведи значение для " + i + ": ");
int currentValue = in.nextInt();
if (currentValue > max){
max = currentValue;
}
}
System.out.println(max);
}
}
Давайте попробуем составить алгоритм действий и в то же время пройтись по вашему коду, проверяя, все ли пункты правильно выполнены и нет ли ничего лишнего.
- Получаем от пользователя количество чисел и инициализируем массив, предварительно проверяя, что длинна массива не меньше 1.
Ваши ошибки на этом шаге:
- Массива почему-то 2:
aиarr. Нужен только один. Пусть это будетarray. - Переменные лучше называть говорящими и понятными именами. Поэтому
inлучше заменить наScanner, аnнапример наlength. - Нужно проверить, что пользователь ввёл корректную длину массива (то есть не 0 и не отрицательное число). Можно сделать так, что программа не пойдёт дальше, пока число не будет правильным.
Тогда код из этого пункта алгоритма будет такой:
Scanner scanner = new Scanner(System.in);
int length = 1;
while(true){
System.out.println("Сколько будет значений?");
length = scanner.nextInt();
if(length < 1) System.err.println("Длинна массива не может быть " + length + "!");
else break;
}
int[] array = new int[length];
- Объявляем переменную и приравниваем её минимальному значению типа
int. Здесь у меня вопрос: почему у вас переменная называетсяmax3? Почему не простоmax(а лучше быmaxNumber)?
Минимальное значение типа int удобно взять из константы MIN_VALUE класса Integer:
int maxNumber = Integer.MIN_VALUE;
- Получаем числа от пользователя. На этом этапе ошибка одна: эти размножающиеся массивы. Массив нужен только один. Реализация этого пункта алгоритма может выглядеть так:
for(int i = 0; i < array.length; i++){
System.out.println("Введи следующий индекс массива:");
array[i] = scanner.nextInt();
}
- Собственно ищем максимум (в том же самом цикле, где просили вводить пользователя числа). Это реализовано у вас правильно, но можно записать
ifкороче:
if(array[i] > maxNumber) maxNumber = array[i];
- Выводим максимум на экран.
P.S: прошу внимательно прочитать ответ и понять все ошибки. Тогда вы без труда склеите приведённые лоскутки кода в единое целое.
Проблема, указанная в заголовке вопроса: Почему поиск максимального значения в массиве происходит неверно: вместо 10 выводится 7? НЕ воспроизводится из-за ошибок в коде, которые необходимо исправить:
- Ошибки при объявлении переменных.
В "классическом" стиле программирования требовалось сначала объявить переменные, и только затем заниматься действиями с ними, включая инициализацию. В данном случае это привело к путанице с именем массива.
Чтобы избежать таких ошибок, достаточно объявлять переменные непосредственно при присваивании их значений, чтобы не было лишнего кода между объявлением и присваиванием. Также следует определиться с названием массива.
Scanner in = new Scanner(System.in);
System.out.println("Сколько будет значений?");
int n = in.nextInt();
int[] arr = new int[n];
// ...
- Инициализация максимума.
В исходном коде максимум инициализируется первым членом массива до того как массив был создан. Но даже если непустой массив был создан правильно, он будет содержать нули, и соответственно максимуму будет присвоено значение 0, что приведёт к неправильному решению, если при вводе массив будет заполнен только отрицательными значениями.
В своём ответе Зонтик проинициализировал максимум наименьшим целочисленным значением Integer.MIN_VALUE, что вполне приемлемо для заведомо непустого массива.
Однако следует учесть, что n = 0 является вполне допустимым размером массива, тогда он будет пустой, и максимум как таковой вообще не будет существовать.
То есть, имеет смысл объявить переменную для хранения максимума так:
Integer max = null;
Также для поиска максимума можно использовать стандартный метод Math.max, с проверкой текущего максимума:
for (int i = 0; i < n; i++) {
System.out.println("Введи значение для " + i + ": ");
arr[i] = in.nextInt();
max = Math.max(arr[i], max == null ? Integer.MIN_VALUE : max);
}
System.out.println(max);
Такое решение корректно обработает ситуации для корректной длины массива (неотрицательного числа), и найдёт максимум для любых элементов массива.
В случае неправильного ввода / отрицательной величины массива будут выброшены соответствующие непроверяемые исключения.
Однако даже исправленное решение представляет собой "монолит", где один метод отвечает за ввод данных, их обработку (поиск максимума) и вывод результата.
Поэтому имеет смысл улучшить приведённое решение, разбив исходную задачу на подзадачи при помощи отдельных методов, чтобы каждый из них отвечал за своё действие:
- создаёт входной массив целых чисел (при помощи сканера потока ввода)
- ищет максимум в массиве
- объединяет вызовы двух вышеупомянутых методов и выводит результаты.
Исправленное решение можно представить в виде отдельного класса FindMax и класса-драйвера Main:
public class Main {
public static void main(String ... args) {
new FindMax().execute();
}
}
Код станет более структурированным:
public class FindMax {
public void execute() {
int[] arr = inputArray();
System.out.println("Введён массив: " + Arrays.toString(arr));
Integer max = findMax(arr);
System.out.println(max);
}
protected int[] inputArray() {
Scanner in = new Scanner(System.in);
System.out.println("Введите размер массива: ");
int[] arr = new int[in.nextInt()];
for (int i = 0; i < arr.length; i++) {
arr[i] = in.nextInt();
}
return arr;
}
protected Integer findMax(int ... arr) {
Integer max = null;
for (int x : arr) {
max = null == max ? x : Math.max(x, max.intValue());
}
return max;
}
}
Такая организация кода (см. шаблонный метод) позволит в дальнейшем переопределить реализации методов как ввода, так и поиска максимума, например с помощью Stream API код можно значительно сократить:
class FindMaxStream extends FindMax {
protected int[] inputArray() {
Scanner in = new Scanner(System.in);
System.out.println("Введите размер массива: ");
return IntStream.generate(in::nextInt).limit(in.nextInt()).toArray();
}
protected Integer findMax(int ... arr) {
OptionalInt max = Arrays.stream(arr).max();
return max.isPresent() ? max.getAsInt() : null;
}
}
