В службе экспресс-доставки посылки распределяются по трем типам ячеек постамата в зависимости от двух параметров — веса и длины самой длинной стороны коробки:

  • Малая ячейка: вес до 2 кг включительно, длина до 20 см включительно.
  • Средняя ячейка: вес до 10 кг включительно, длина до 50 см включительно.
  • Большая ячейка: вес до 30 кг включительно, длина до 120 см включительно.
  • Если вес превышает 30 кг или длина больше 120 см, посылка считается негабаритной и отправляется на грузовой склад.

Курьер привез коробку со следующими параметрами: вес 1.5 кг, длина 35 см.

  1. В какую ячейку должна попасть эта посылка?
  2. Почему проверки одного только веса недостаточно и в каком порядке нужно проверять оба параметра, чтобы коробка не оказалась в слишком маленькой ячейке?
  3. Попробуйте записать последовательность этих действий обычными словами в виде 4–5 четких правил так, чтобы любой человек выполнил сортировку без подсказок.

Обсуждение гипотезыНаставник поможет уточнить мысльПопытка 1 из 3
Наставник

Предложите свою версию. Здесь не нужен идеальный ответ: важно показать ход мысли. Если понадобится, я задам один наводящий вопрос.

Каждый, кто начинает программировать, неизбежно попадает в одну и ту же психологическую ловушку: получив задачу, мы сразу открываем редактор кода и начинаем писать строки на C#. Руки тянутся объявлять переменные, выстраивать цепочки if-else, открывать фигурные скобки и запускать циклы.

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

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

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

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

Главные инструменты такого предварительного проектирования — блок-схемы и псевдокод.

Блок-схемы: визуализация потока решений

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

Для построения схем используется стандартный набор геометрических блоков, соединенных стрелками (линиями потока):

  • Терминатор (скругленный прямоугольник или овал): обозначает точку старта или завершения программы.
  • Ввод/Вывод (параллелограмм): получение данных извне (например, считывание параметров посылки) или выдача итогового ответа на экран.
  • Процесс (прямоугольник): конкретное вычислительное действие, расчет значения или присвоение переменной.
  • Решение (ромб): проверка логического условия с обязательным ветвлением. Из ромба всегда выходят как минимум две стрелки: «Да» (условие выполнено) и «Нет» (условие нарушено).

Давайте посмотрим, как логика сортировки посылок выглядит в виде схемы:

flowchart LR accTitle: Выбор ячейки постамата accDescr: Блок-схема последовательно проверяет корректность размеров посылки, негабаритный груз и подходящий размер ячейки. START([Начало]) --> INPUT[/Вес и длина/] INPUT --> VALID{Вес ≤ 0 или длина ≤ 0?} VALID -- Да --> ERROR[/Ошибка/] ERROR --> END([Конец]) VALID -- Нет --> OVERSIZE{Вес > 30 или длина > 120?} OVERSIZE -- Да --> CARGO[/Грузовой склад/] CARGO --> END OVERSIZE -- Нет --> SMALL{Вес ≤ 2 и длина ≤ 20?} SMALL -- Да --> SMALL_BOX[/Малая ячейка/] SMALL_BOX --> END SMALL -- Нет --> MEDIUM{Вес ≤ 10 и длина ≤ 50?} MEDIUM -- Да --> MEDIUM_BOX[/Средняя ячейка/] MEDIUM_BOX --> END MEDIUM -- Нет --> LARGE_BOX[/Большая ячейка/] LARGE_BOX --> END

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

  1. Нет тупиков: из каждого блока есть понятный выход, ни одна стрелка не обрывается в пустоте.
  2. Очевиден порядок проверок: мы сначала отсекаем ошибочные данные, затем проверяем негабаритный груз, и лишь потом выбираем размер ячейки от меньшего к большему.
  3. Отсутствует дублирование: если посылка не поместилась в малую ячейку, на следующем шаге нам не нужно проверять вес > 2, ведь мы попали на ветку «Нет» именно потому, что малые габариты были превышены.

Блок-схема великолепно подходит для обсуждения архитектуры с коллегами и быстрого поиска логических дыр.

Псевдокод: четкий текст без синтаксического шума

Когда логика программы разрастается, рисовать подробные геометрические схемы становится неудобно. На смену диаграммам приходит псевдокод (pseudocode).

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

Хороший псевдокод опирается на простые правила:

  • Одно действие — одна строка. Не нужно склеивать несколько операций в длинные фразы.
  • Структурные отступы. Вложенность внутри условий и циклов оформляется визуальными пробелами.
  • Понятные ключевые слова. Используются базовые конструкции управления: ЕСЛИ, ИНАЧЕ ЕСЛИ, ИНАЧЕ, ПОКА, ДЛЯ КАЖДОГО, ВЕРНУТЬ.

Запишем наш алгоритм сортировки на псевдокоде:

ФУНКЦИЯ ВыбратьЯчейку(вес, длина)
    ЕСЛИ вес <= 0 ИЛИ длина <= 0 ТОГДА
        ВЕРНУТЬ "Ошибка: некорректные параметры"

    ЕСЛИ вес > 30 ИЛИ длина > 120 ТОГДА
        ВЕРНУТЬ "Грузовой склад"

    ЕСЛИ вес <= 2 И длина <= 20 ТОГДА
        ВЕРНУТЬ "Малая"
    ИНАЧЕ ЕСЛИ вес <= 10 И длина <= 50 ТОГДА
        ВЕРНУТЬ "Средняя"
    ИНАЧЕ
        ВЕРНУТЬ "Большая"
КОНЕЦ ФУНКЦИИ

Посмотрите, насколько легко читать этот текст. В нем нет синтаксического шума C#, но структура решения зафиксирована абсолютно однозначно.

Ручная трассировка: тест на бумаге до компиляции

После того как алгоритм записан на псевдокоде, его необходимо проверить на конкретных тестовых значениях. Этот процесс называется трассировкой (tracing) — пошаговым ручным исполнением алгоритма с отслеживанием состояния переменных.

Проверим наш алгоритм на трех контрольных примерах.

Тест 1. Обычный случай: вес = 1.5 кг, длина = 35 см

  1. Проверяем вес <= 0 ИЛИ длина <= 0: условие ложно (1.5 > 0 и 35 > 0). Идем дальше.
  2. Проверяем вес > 30 ИЛИ длина > 120: условие ложно (1.5 <= 30 и 35 <= 120). Идем дальше.
  3. Проверяем вес <= 2 И длина <= 20: вес подходит (1.5 <= 2), но длина не подходит (35 > 20). Общее условие ложно. Переходим к следующей ветке.
  4. Проверяем вес <= 10 И длина <= 50: оба условия истинны (1.5 <= 10 и 35 <= 50).
  5. Результат: алгоритм возвращает "Средняя". Ответ верный.

Тест 2. Граничное значение: вес = 2.0 кг, длина = 20.0 см

  1. Первые две проверки на ошибки и негабарит возвращают Ложь.
  2. Проверяем вес <= 2 И длина <= 20: оба равенства выполняются благодаря нестрогому знаку <=.
  3. Результат: алгоритм возвращает "Малая". Ответ верный, граница диапазона отработала точно.

Тест 3. Некорректный ввод: вес = -4 кг, длина = 15 см

  1. Проверяем вес <= 0 ИЛИ длина <= 0: вес отрицательный, условие истинно.
  2. Результат: алгоритм немедленно возвращает "Ошибка: некорректные параметры", не допуская выполнение бессмысленных расчетов для несуществующего груза.

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

Перенос в код на C#

Когда логический каркас проверен и подтвержден трассировкой, написание программы на C# превращается в спокойную, почти механическую работу по переводу готовой инструкции на синтаксис языка:

public enum CellCategory
{
    Small,
    Medium,
    Large,
    HeavyFreight,
    InvalidInput
}

public class LockerDistributionService
{
    public static CellCategory DetermineCell(double weightKg, double lengthCm)
    {
        // Проверка входных данных на корректность
        if (weightKg <= 0 || lengthCm <= 0)
        {
            return CellCategory.InvalidInput;
        }

        // Проверка на негабаритный груз
        if (weightKg > 30 || lengthCm > 120)
        {
            return CellCategory.HeavyFreight;
        }

        // Подбор ячейки по габаритам
        if (weightKg <= 2 && lengthCm <= 20)
        {
            return CellCategory.Small;
        }

        if (weightKg <= 10 && lengthCm <= 50)
        {
            return CellCategory.Medium;
        }

        return CellCategory.Large;
    }
}

Обратите внимание: мы сосредоточились исключительно на качестве реализации. Мы оформили возвращаемые значения в виде типизированного перечисления enum CellCategory, использовали тип double для поддержки дробных килограммов и сантиметров и разделили проверки понятными комментариями. Мы не тратили силы на придумывание логики на ходу — она была полностью готова заранее.

Универсальность логического мышления

Псевдокод и схемы не зависят от конкретной программной платформы. Тот же самый алгоритм сортировки посылок можно за пять минут переписать на любом другом языке:

  • В Python мы заменим фигурные скобки двоеточиями и отступами.
  • В JavaScript мы используем ключевые слова function и const.
  • В Go мы вернем значение и ошибку отдельными параметрами.

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

Псевдокод как общий язык команды

До появления C#-кода логику могут проверить все участники задачи. Разработчик видит порядок условий, тестировщик выписывает граничные случаи, а автор требований замечает пропущенное правило. Им не приходится одновременно разбираться в типах, скобках и именах методов.

В примере с постаматом такая проверка быстро обнаруживает опасные места: отрицательный вес, границы 2 и 20, а также необходимость проверять оба параметра ячейки. После согласования псевдокод становится договорённостью о поведении программы. Реализацию можно переписать на другом языке, но эта договорённость сохранится.

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


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

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

Спроектированный алгоритм легко переносится на C#, Java, Python, Go или JavaScript. Псевдокод фиксирует договорённость о поведении программы, а ручная трассировка помогает превратить эту договорённость в конкретные тестовые случаи.

В следующем уроке — «Оценка сложности алгоритмов: нотация O(n), O(1), O(log n), O(n²)» — мы перейдем к фундаментальному инструменту анализа программ: научимся измерять вычислительную стоимость алгоритмов объективным языком математики, отбрасывать случайные факторы и точно предсказывать, как поведет себя код при любом масштабе входных данных.

Обсуждение урока

0
Комментарии видны всем. Чтобы участвовать в обсуждении, войдите или зарегистрируйтесь.
Модерация сообщества

Пожаловаться на комментарий

Расскажите модераторам, что именно требует внимания.