Этапы решения алгоритмических задач и немного о шаблонах кода

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

25 июля 2026 г.

Алгоритм решения задач

Решение задачи строим следующим образом:

  1. Постановка задачи (Problem Definition). Учащиеся должны определить, что дано и что нужно найти. Кроме этого они должны определить типы входных и выходных данных и как эти данные будут представлены в программе.
  2. Конкретные примеры (Concrete Cases). Учащиеся подбирают конкретные входные данные и находят способ получить для них выходные значения. Со временем ученики обстрагируются от конкретных данных и обобщают алгоритм решения для произвольных значений1. При необходимости уточняются типы данных, выбранные на первом этапе. Не лишним будет продумать имена для переменных.
  3. Проектирование алгоритма (Design of Algorithm). Переходим к описанию алгоритма решения задачи на естественном языке. На этом шаге учащиеся перечисляют шаги благодаря которым они получили выходные значения для каждого конкретного примера. Обращаем внимание учащихся на общие для каждого примера шаги - повторяющиеся шаблоны. Обобщённый алгоритм записывается на смеси естественного языка, псевдокода или в форме блок-схемы. Уделяем особое внимание фразам-маякам в описании алгоритма: “для каждого элемента …”, “сложить значения …”, “найти сумму …” и т.д. Эти фразы подскажут, какие синтаксические конструкции и шаблоны нужно использовать при кодировании решения на языке программирования.
  4. Реализация (Implementation). Учащиеся переводят решение из псевдокода на язык программирования. Этот этап тесно связан со следующим.
  5. Тестирование (Testing). Напоминаем учащимся периодически проверять работоспособность кода. Не нужно впервые запускать программу только после записи последней строки кода. Периодическое тестирование программы особенно полезно для начинающих программистов. В таком случае ошибки не накапливаются и отладка программы происходит небольшими порциями. Каждый успешный запуск кода повышает мотивацию двигаться дальше. Для итогового тестирования подойдут данные из второго этапа.

На рисунке показана схема подхода. Сокращённо назовём этот подход ПКПРТ.

Рисунок 1

С подробностями можно ознакомиться в оригинале статьи [2] .

Пример решения задачи

Дан список температур за неделю. Подсчитать количество дней с отрицательной температурой и сумму модулей отрицательных значений температур.

Определим входные и выходные данные. Входные данные: список вещественных чисел temps. Выходные данные: количество дней с отрицательной температурой count - целое число, сумма модулей отрицательных температур summ - вещественное число.

Рисунок 2

Посмотрим на конкретный пример: список [5, -2, 0, -5, 3, 1, -1]. В этом случае количество равно 3, а сумма модулей температур равна 8.0. В реальной ситуации нужно продумать больше одного тестового случая. Так учащимся будет проще искать шаблоны решения.

Спроектируем алгоритм. В начале счётчик и сумма равны нулю. Чтобы посчитать количество и сумму, нужно перебрать все элементы списка. Для каждого элемента проверяем, меньше ли он 0. Если это так, то к счётчику прибавим 1, а к сумме прибавим модуль значения этого элемента. Выведем значения счётчика и суммы на экран. В псевдокоде решение выглядит так:

заполнить список temps значениями

count = 0
summ = 0

для каждого элемента из списка temps
    если элемент меньше нуля то
        увеличить count на 1
        увеличить сумму на модуль элемента
        
вывести count
вывести summ

Реализуем алгоритм на Python:

temps = [5, -2, 0, -5, 3, 1, -1]

count = 0      # счётчик
summa = 0.0    # аккумулятор

for t in temps:
    if t < 0:
        count += 1
        summa += abs(t)

print(f"Дней с отрицательной температурой: {count}")
print(f"Сумма модулей отрицательных температур: {summa} C")

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

Как внедрить на занятии

Следует рассказать учащимся о ПКПРТ-подходе после перехода к задачам, решение которых подразумевает наличие ветвления, циклов и составных типов данных.

Все этапы подхода рассматриваем на примере задачи. Следующий шаг - самостоятельная реализация этапов на примере новой задачи. Результаты обсуждения каждого этапа проверяются преподавателем, чтобы выявить пробелы в понимании алгоритма решения. Озвучиваем учащимся важный тезис - написанию кода решения предшествует подготовительная работа.

“Цели” и “планы”

В заметке я многократно упомянул шаблоны программирования. Что это такое и почему полезно явно делать на них акцент на занятиях с учащимися? Для ответа на этот вопрос буду ссылаться на публикацию [3] .

У кода есть два “читателя”:

  • компьютер: программные инструкции создают механизм решения задачи;

  • человек: должен понимать почему эти инструкции приводят к верному решению - объяснение эффективности алгоритма.

В таком случае, научиться программировать - значит научиться конструировать механизм решения и уметь объяснить, почему это решение корректно и эффективно.

В публикации [3] для обозначения стратегий решения задач используются термины цель и план (goals and plans). Под комбинацией цели и плана понимается стереотипное, устоявшееся и проверенное временем решение типовой задачи. В итоге для решения задачи нужно разбить её на подзадачи решение которых уже известно программисту и шаблоны для решения подобных задач уже усвоены.

Набор шаблонов я приведу в следующем разделе, но пока что покажу пример решения задачи из публикации.

Напишите программу, которая считывает целые числа с клавиатуры и выводит на экран их среднее значение. Ввод чисел прекращается после числа 99999.

На иллюстрации показаны цели и планы (шаблоны) для их реализации и то, как их объединение приводит к решению задачи.

Рисунок 3: Использование шаблонов для решения задачи (нажмите, чтобы увеличить)

Каждый шаблон на рисунке обозначен своим цветом. В коде решения обозначено, какие строки реализуют тот или иной шаблон. Как видно из иллюстрации, шаблоны перемешиваются и объединяются. Согласно [3] , объединение шаблонов вызывает большие трудности для учащихся. Авторы выделяют четыре стратегии объединения шаблонов:

  • Сложение: два плана следуют друг за другом. В примере шаблон “Цикл с часовым” и “Альтернатива” следуют по-порядку.

  • Вложенность: один шаблон полностью располагается внутри другого. В примере шаблоны “Деление” и “Вывод на экран” не выходят за пределы шаблона “Альтернатива”.

  • Слияние: по меньшей мере два шаблона пересекаются. В примере шаблоны для поиска суммы и количества чисел необходимо объединить между собой.

  • Адаптация: среди изученных шаблонов не всегда найдётся подходящий. В таком случае придётся модифицировать шаблон чтобы адаптировать его под текущую задачу.

Стоит отметить, изучение программирования не должно строится только на изучении шаблонов. В публикации [1] приводится список упражнений, которые способствуют процессу изучения и усвоения шаблонов программирования:

  • упражнения на чтение и понимание существующего кода (см. Блочная модель);
  • поиск схожих и различных элементов в нескольких примерах кода;
  • обобщение кода примеров для самостоятельного “изобретения” шаблона;
  • повторное использование кода примеров;
  • перечисление шаблонов, подходящих для решения задачи;
  • сравнение схожих шаблонов.

В статье [1] также упоминается создание библиотеки шаблонов для учащихся. Каждый шаблон в каталоге содержит текстовое описание, псевдокод, комментарии преподавателя и студентов, статичные и анимированные иллюстрации, область применения шаблона. В следующем разделе заметки приведу примеры шаблонов о которых я рассказывал студентам на своих занятиях.

С понятием шаблонов тесно связана классификация переменных по их роли в алгоритме [4] . О ролях переменных есть своя заметка в блоге.

Библиотека шаблонов

Обновление значения переменной

Цель: обновить значение переменной, используя её текущее значение и некое выражение.

Шаблон: в общем виде обновление значения запишем следующим образом.

<переменная> = <переменная> <оператор> <выражение>

Пример:

print(age)
age = age + 1 # увеличиваем значение переменной age на единицу
print(age)

Обмен значениями

Цель: поменять местами два значения, хранящиеся в переменных.

Шаблон: используем временную переменную для обмена.

Пример:

a = 1
b = 2
print(a, b)

temp = a
a = b
b = temp
print(a, b)

В Python обмен может быть записан через позиционное присваивание:

a, b = b, a

Инструкция под защитой

Цель: выполнение блока инструкций определяется значением логического выражения.

Шаблон:

если <условие> то
    <блок инструкций>

Пример:

temperature = 15.1

if temperature < 18.0:
    print("Включаю нагреватель")
print("Программа завершена")

Альтернатива

Цель: выполнить один из двух блоков инструкций исходя из условия. Варианты инструкций взаимоисключают друг друга.

Шаблон:

если <условие> то
    <блок инструкций 1>
иначе
    <блок инструкций 2>

Пример:

grade = 8
if grade >= 4:
    print("Тест пройден!")
else:
    print("Повторите попытку.")

Каскад решений

Цель: выполнить один из нескольких блоков инструкций исходя из условия. В каждом проверяемом условии есть минимум одно общее для всех условий выражение или переменная.

Шаблон:

если <условие 1>
    <блок инструкций 1>
иначе если <условие 2>
    <блок инструкций 2>
...
иначе если <условие n>
    <блок инструкций n>
иначе
    <действие по умолчанию>

Пример:

score = int(input("Баллы:"))

if score >= 80:
    print("Отлично")
elif score >= 60:
    print("Хорошо")
elif score >= 40:
    print("Удовлетворительно")
else:
    print("Неудовлетворительно")

Обход последовательности

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

Шаблон:

для <значения> в <последовательности>
    <блок инструкций>

Примеры:

v0 = 5   # начальная скорость
a = 2    # ускорение

for t in range(11):
    s = v0 * t + a * t ** 2 / 2
    print(f"t = {t} с,  s = {s} м")
U = [3.2, 4.7, 2.1, 5.0, 3.8]
R = 10

for v in U:
    I = v / R
    print(f"I={I} А")

Аккумулирование

Цель: “накопить” в одной переменной значения элементов заданной последовательности (сложение, произведение и другие операторы).

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

Примеры:

# сумма элементов списка

lst = [1, 1, 2, 3, 5, 8]

summa = 0 # начальное значение аккумулятора
for el in lst: # обход последовательности
    summa = summa + el # обновление значения переменной
# аккумулирование строки
st = "игра"

rev = "" # начальное значение аккумулятора
for i in range(len(st)-1, -1, -1): # обход последовательности индексов
    rev = rev + st[i] # обновление значения переменной
    
print(rev)

Подсчёт

Цель: получить количество элементов последовательности удовлетворяющих заданному условию.

Шаблон: инициализировать переменную-счётчик значением 0. Начать обход последовательности. Если очередной элемент удовлетворяет условию, обновить значение переменной-счётчика.

Пример:

# найти количество чётных элементов в списке
lst = [1, 1, 2, 3, 5, 8]

count = 0 # инициализация счётчика

for el in lst:
    if el % 2 == 0:
        count = count + 1

print(count)

Поиск min/max

Цель: нужно найти наибольшее или наименьшее значение в наборе данных.

Шаблон: понадобится «Хранитель наилучшего значения»: переменная, которая на каждом шаге хранит наилучшее из просмотренных значений и обновляется при нахождении более подходящего элемента. Переменная должна быть инициализирована первым элементом последовательности, а не произвольным числом.

Пример:

# поиск максимально значения в списке masses

masses = [3.30e23, 4.87e24, 5.97e24, 6.42e23]  # массы планет, кг

# Хранитель наилучшего значения: первый элемент списка
max_mass = masses[0]

for m in masses:
    if m > max_mass:
        max_mass = m  # обновление при нахождении более подходящего значения

print(f"Наибольшая масса: {max_mass} кг")

Цикл с часовым

Цель: обрабатываются данные, поступающие до появления специального признака остановки (часового). Количество поступающих значений заранее неизвестно.

Шаблон:

считать значение
пока значение не равно часовому
    обработка значения
    считать значение

Пример:

# найти общую массу осадка, пока значения больше 0

total = 0.0   # аккумулятор

value = float(input("Масса осадка: "))
while value > 0:
    total += value
    value = float(input("Масса осадка: "))

print(f"общая масса: {total:.2f} г")

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

использованная литература

1. Clancy M. J., Linn M. C. Patterns and pedagogy SIGCSE ’99 / New York, NY, USA: Association for Computing Machinery, 1999.C. 3742.
2. Kurniawan O. [и др.]. Steps Before Syntax: Helping Novice Programmers Solve Problems using the PCDIT Framework 2022.
3. Soloway E. Learning to program = learning to construct mechanisms and explanations // Commun. ACM. 1986. № 9 (29). C. 850–858.
4. Sorva J., Karavirta V., Korhonen A. Roles of Variables in Teaching // Journal of Information Technology Education: Research. 2007. (6). C. 407–423.

Сноски

  1. Этот шаг многократно помогал мне решать непростые алгоритмические задачи. Ведь пока пытаешся найти закономерность связывающую входные и выходные данные, можешь натолкнуться на алгоритм решения.↩︎