Массивы и циклы: типовые задачи с решениями

Обход массива, поиск минимума и максимума, суммы и средние, реверс и сдвиг, работа с двумерными массивами, вложенные циклы и типовые ошибки индексации.

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

Накопление

a = [4, -2, 7, 0, 15, -8, 3]

total = 0
count = 0
for x in a:
    if x > 0:
        total += x
        count += 1

avg = total / count if count else 0
print(f'сумма положительных {total}, среднее {avg:.2f}')
Проверка count перед делением — не формальность. Массив без единого подходящего элемента даёт деление на ноль, и программа падает ровно на защите, когда преподаватель вводит свои данные.

Поиск минимума и максимума

a = [4, -2, 7, 0, 15, -8, 3]

min_val, min_idx = a[0], 0
for i in range(1, len(a)):
    if a[i] < min_val:
        min_val, min_idx = a[i], i

print(f'минимум {min_val} в позиции {min_idx}')

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

// То же на C++
#include <iostream>
using namespace std;

int main() {
    const int N = 7;
    int a[N] = {4, -2, 7, 0, 15, -8, 3};

    int minVal = a[0], minIdx = 0;
    for (int i = 1; i < N; ++i) {
        if (a[i] < minVal) { minVal = a[i]; minIdx = i; }
    }
    cout << "минимум " << minVal << " в позиции " << minIdx << endl;
    return 0;
}

Перестановки элементов

# Реверс на месте, без дополнительного массива
a = [1, 2, 3, 4, 5]
for i in range(len(a) // 2):
    a[i], a[-1 - i] = a[-1 - i], a[i]
print(a)   # [5, 4, 3, 2, 1]

# Циклический сдвиг влево на k позиций
def rotate_left(a, k):
    k %= len(a)
    return a[k:] + a[:k]

print(rotate_left([1, 2, 3, 4, 5], 2))   # [3, 4, 5, 1, 2]

# Удаление элементов без создания нового массива
def remove_negatives(a):
    write = 0
    for read in range(len(a)):
        if a[read] >= 0:
            a[write] = a[read]
            write += 1
    del a[write:]
    return a

Приём с двумя индексами — чтения и записи — стандартный для удаления элементов за один проход. Он же лежит в основе алгоритмов сжатия массивов и работает за O(n) без дополнительной памяти.

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

m = [[1, 2, 3],
     [4, 5, 6],
     [7, 8, 9]]

# Сумма по строкам
for i, row in enumerate(m):
    print(f'строка {i}: {sum(row)}')

# Сумма по столбцам
for j in range(len(m[0])):
    s = sum(m[i][j] for i in range(len(m)))
    print(f'столбец {j}: {s}')

# Главная и побочная диагонали
n = len(m)
main = sum(m[i][i] for i in range(n))
side = sum(m[i][n - 1 - i] for i in range(n))
print(f'главная {main}, побочная {side}')

# Транспонирование
t = [[m[i][j] for i in range(len(m))] for j in range(len(m[0]))]
Условие на индексыЧто выделяет
i == jГлавная диагональ
i + j == n − 1Побочная диагональ
i < jВыше главной диагонали
i > jНиже главной диагонали
(i + j) % 2 == 0Клетки одного цвета в шахматном порядке
Создавать двумерный массив в Python через [[0]*m]*n нельзя: получится n ссылок на одну и ту же строку, и запись в одну ячейку изменит целый столбец. Правильно: [[0]*m for _ in range(n)].

Вложенные циклы

# Таблица умножения
for i in range(1, 6):
    for j in range(1, 6):
        print(f'{i*j:4}', end='')
    print()

# Пузырьковая сортировка с ранним выходом
def bubble_sort(a):
    n = len(a)
    for i in range(n - 1):
        swapped = False
        for j in range(n - 1 - i):
            if a[j] > a[j + 1]:
                a[j], a[j + 1] = a[j + 1], a[j]
                swapped = True
        if not swapped:      # массив уже отсортирован
            break
    return a

Флаг swapped превращает худшие O(n²) в лучшие O(n) на почти отсортированных данных. Такую деталь стоит упомянуть в отчёте: она показывает, что вы понимаете алгоритм, а не переписали его из учебника.

Ошибки индексации

ОшибкаПроявлениеКак избежать
range(len(a)) с обращением к a[i+1]Выход за границу на последнем шагеrange(len(a) - 1)
Изменение массива внутри цикла по немуПропуск элементовИдти по копии или собирать новый список
Индекс с единицыПропущен первый элементПомнить, что нумерация с нуля
Сравнение i <= len(a)Выход за границуСтрого i < len(a)

Что писать в отчёте

  1. Постановка задачи и формат входных данных.
  2. Блок-схема алгоритма или его словесное описание.
  3. Листинг с комментариями — в приложение, если он длиннее страницы.
  4. Таблица тестов: обычные данные, граничные (пустой массив, один элемент), некорректный ввод.
  5. Оценка сложности по времени и памяти.

Частые вопросы

Чем массив отличается от списка в Python?

Список — динамическая структура переменной длины с элементами любых типов. Массив (numpy или модуль array) хранит однотипные элементы подряд в памяти, работает быстрее и экономичнее, но размер фиксирован.

Почему индексация начинается с нуля?

Индекс — это смещение от начала массива в памяти. У первого элемента смещение нулевое, поэтому адрес вычисляется как база + i·размер_элемента без лишнего вычитания.

Как обойти двумерный массив по спирали?

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

Читайте также

Сделаем работу по этой теме

Опишите задачу — ответим в течение 15 минут в личных сообщениях ВКонтакте, назовём срок и цену. Предоплаты за оценку нет.

  • Оценка заявки бесплатно
  • Правки по замечаниям преподавателя
  • Работы по всем техническим и IT-дисциплинам

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