Към съдържанието
wannacode

Масиви

Проблем

Тридесет оценки

Учител пише програма за оценките от контролното. За петима ученици прави пет променливи:

int score1 = 62;
int score2 = 85;
int score3 = 47;
int score4 = 91;
int score5 = 78;
int sum = score1 + score2 + score3 + score4 + score5;
System.out.println(sum);
Изход
363

В класа обаче са тридесет. Тридесет променливи, тридесет събираеми. А за най-високия резултат трябват още двадесет и девет сравнения. Цикълът от миналия урок не помага: той не може да мине през score1, score2, score3, защото това са отделни имена. Трябват ни много стойности под едно име.

Идеята

Масив: редица от кутийки

Масивът е редица от стойности от един тип под едно име. Всяка стойност, елемент на масива, има номер: индекс. Индексите започват от 0.

int[] scores = { 62, 85, 47, 91, 78 };
System.out.println(scores[0]);
System.out.println(scores[4]);
System.out.println(scores.length);
scores[2] = 50;
System.out.println(scores[2]);
Изход
62
78
5
50
  • int[] е типът: „масив от int“. Стойностите са в { }.
  • scores[0] е първият елемент, scores[4] петият. Последният индекс е винаги с 1 по-малък от броя.
  • scores.length е броят на елементите. Тук е 5.
  • scores[2] = 50; сменя един елемент. Останалите не се променят.

Ако още не знаеш стойностите, създаваш масива само с размер. Тогава всички елементи са 0:

int[] booked = new int[3];
booked[1] = 2;
System.out.println(booked[0] + " " + booked[1] + " " + booked[2]);
Изход
0 2 0

Размерът се определя при създаването и после не се сменя.

По-точно, за любопитните
  • Индексите са само от 0 до броя минус 1. Отрицателен индекс е извън масива.

Пробвай

Кой е кой?

Какво ще отпечата програмата?

int[] prices = { 12, 7, 30, 5 };
System.out.println(prices[1] + prices[3]);
Отговор

Идеята

Цикъл през масива

Сега цикълът вече помага. Броячът i става индексът: минава от 0 до последния и на всеки кръг взима scores[i].

int[] scores = { 62, 85, 47, 91, 78 };
int sum = 0;
for (int i = 0; i < scores.length; i++) {
sum += scores[i];
}
System.out.println("Сума: " + sum);
System.out.println("Средно: " + (double) sum / scores.length);
Изход
Сума: 363
Средно: 72.6

Условието е i < scores.length, а не число. Добавиш ли тридесетте оценки в { }, цикълът не се променя. Това се казва обхождане на масива.

(double) е нужно заради целочисленото деление: 363 / 5 е 72, а ни трябва 72,6.

Виж го

Най-високият резултат

Как намираш най-голямото число? Помниш най-голямото засега и го сменяш, щом видиш по-голямо.

int[] scores = { 62, 85, 47, 91, 78 };
int max = scores[0];
for (int i = 1; i < scores.length; i++) {
if (scores[i] > max) {
max = scores[i];
}
}
System.out.println(max); // 91
Стъпка по стъпка, с думи
  1. Пет резултата, едно до друго. Номерата отдолу са индексите: от 0 до 4.
  2. max започва от първия: scores[0] е 62.
  3. i = 1: 85 > 62, max става 85.
  4. i = 2: 47 не е по-голямо от 85. Нищо не се сменя.
  5. i = 3: 91 > 85, max става 91.
  6. i = 4: 78 < 91. После i става 5, 5 < scores.length е невярно и цикълът спира.
  7. Най-големият резултат е 91.

max започва от първия елемент, а не от 0. Ако всички резултати бяха отрицателни, 0 щеше да „спечели“, без да е в масива. Затова и цикълът започва от i = 1: първият вече е в max.

Пробвай

Намери грешката

Програмата трябва да отпечата сумата 363. Вместо това спира с грешка:

Грешка
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5

На кой ред е грешката?

Избери реда с грешката.

Идеята

for-each: за всеки елемент

Когато ти трябват само стойностите, а не индексите, има по-кратък цикъл. Колко ученици са взели изпита (60 точки и нагоре)?

int[] scores = { 62, 85, 47, 91, 78 };
int passed = 0;
for (int score : scores) {
if (score >= 60) {
passed++;
}
}
System.out.println("Взели изпита: " + passed);
Изход
Взели изпита: 4

Чете се „за всяко score от scores“. Той се казва for-each. Няма брояч и индекс, затова не можеш да излезеш извън масива.

Има и граница: не знаеш на кой индекс си и не можеш да смениш елемента.

По-точно, за любопитните
  • Ако напишеш score = 0; в тялото, сменяш само копието в score. Масивът остава същият. Компилаторът не те спира.
  • За да смениш елементи или да ти трябва индексът (например за съседа scores[i + 1]), ползвай обикновен for.

Пробвай

Две имена, един масив

Какво ще отпечата програмата?

int[] prices = { 10, 20, 30 };
int[] sale = prices;
sale[0] = 5;
System.out.println(prices[0]);
Отговор
По-точно, за любопитните

Истинско копие правиш с нов масив и цикъл:

int[] prices = { 10, 20, 30 };
int[] sale = new int[prices.length];
for (int i = 0; i < prices.length; i++) {
sale[i] = prices[i];
}
sale[0] = 5;
System.out.println(prices[0] + " " + sale[0]);
Изход
10 5

Същото дава и prices.clone().

Пробвай

Подреди редовете

Програмата трябва да намери най-ниската цена. Подреди редовете ѝ.

  1. int[] prices = { 18, 7, 25, 12 };
  2. for (int i = 1; i < prices.length; i++) {
  3. }
  4. if (prices[i] < min) {
  5. min = prices[i];
  6. int min = prices[0];
  7. }
  8. System.out.println(min);

Упражнение

Сметки с масив

Реши задачите в редактора си. Всяка програма първо чете колко са числата, после самите числа, по едно на ред:

Scanner in = new Scanner(System.in);
int n = in.nextInt();
int[] numbers = new int[n];
for (int i = 0; i < n; i++) {
numbers[i] = in.nextInt();
}

1. Сума, четни, нечетни. Отпечатай сумата на всички числа, на четните и на нечетните.

Вход
3
1
2
3
Изход
Сума: 6
Четни: 2
Нечетни: 4

2. Обратно. Създай нов масив със същите числа в обратен ред и го отпечатай на един ред.

Вход
5
1
2
3
4
5
Изход
5 4 3 2 1

3. Най-малко, най-голямо, средно. С едно минаване през масива.

Вход
5
4
9
2
7
4
Изход
Най-малко: 2
Най-голямо: 9
Средно: 5.2

Упражнение

Подреждане и броене

4. Сортиране. Подреди числата от най-малкото към най-голямото. Подсказка: минавай през масива и ако два съседа са в грешен ред, разменяй ги (размяната е от урока за променливите). Повтори, докато няма какво да размениш. Това се казва метод на мехурчето: големите числа „изплуват“ към края.

Вход
5
42
7
19
3
25
Изход
3 7 19 25 42

5. Най-дълга поредица. Намери най-дългата поредица от еднакви числа едно след друго.

Вход
8
2
2
5
5
5
1
5
5
Изход
Числото 5, 3 пъти подред

6. Статистика на оценките. Прочети оценки от 2 до 6 и отпечатай колко са от всеки вид. Подсказка: масив counts с 7 елемента, в който оценката е индексът: counts[grade]++.

Вход
8
6
4
5
6
3
2
6
5
Изход
Отличен (6): 3
Много добър (5): 2
Добър (4): 1
Среден (3): 1
Слаб (2): 1

Още задачи

  • Медиана. Числото по средата на сортирания масив. За 3, 1, 4, 1, 5 медианата е 3. Ако числата са четен брой, медианата е средното на двете в средата: за 7, 1, 3, 9 е (3 + 7) / 2 = 5.
  • Симетричен масив. Чете ли се еднакво отпред назад и отзад напред? 1 2 3 2 1 е симетричен, 1 2 3 1 не е.
  • Римски цифри. Прочети число от 1 до 3999 и го отпечатай с римски цифри: 2024 е MMXXIV, 1994 е MCMXCIV. Подсказка: два масива един до друг, със стойностите 1000, 900, 500, 400, 100, …, 1 и със знаците "M", "CM", "D", "CD", "C", …, "I". Докато числото е поне колкото текущата стойност, добавяй знака и вади стойността.

Тест

Провери се

1. В масива { 62, 85, 47, 91, 78 } на кой индекс е 91?
2. Кой е индексът на последния елемент на масива scores?
3. Какво има в масива веднага след int[] booked = new int[3];?
4. Цикълът е for (int i = 0; i <= scores.length; i++) и чете scores[i]. Какво става?
5. int[] sale = prices; sale[0] = 5; Какво става с prices[0]?

Създаден от Иво Гергов като част от кампанията на Evo Tech за достъпно обучение по програмиране ·