Вложенные ветвления и выбор

Как засовывать одно ветвление внутрь другого и не утонуть в скобках, отступах и «висячих» иначе.

Вложенное ветвление — это условный оператор, который стоит внутри ветки да или нет другого условного оператора. На блок-схеме это «ромб внутри ромба».

В линейном алгоритме команды идут одна за другой. Но реальные задачи редко бывают линейными: чтобы поставить оценку, сначала проверяют, сдан ли экзамен вообще, и только потом — на сколько баллов. Чтобы решить квадратное уравнение, сперва смотрят, не равен ли нулю старший коэффициент, и лишь затем считают дискриминант. Каждый такой «вопрос после вопроса» — это вложенность.

Зачем это нужно

Одного ромба хватает, когда выбор бинарный: число положительное или нет, год високосный или нет. Но как только вариантов становится три и больше, или один вопрос имеет смысл только при определённом ответе на предыдущий, появляется вложенность. Классический школьный пример — перевод процента правильных ответов в оценку: 5 — это «85 и больше», 4 — «от 70 до 84», 3 — «от 50 до 69», иначе 2. Здесь четыре исхода, и одним ромбом их не разрулить.

Ромб внутри ромба

Представьте блок-схему словами. Внешний ромб спрашивает: балл >= 85?. Если да — ставим 5 и выходим. Если нет — попадаем в ветку нет, а там стоит ещё один ромб: балл >= 70?. И так далее. Каждый следующий вопрос живёт внутри ветки нет предыдущего. Текстом блок-схему удобно записать с отступами — отступ показывает уровень вложенности:

[начало]
  |
  V
<балл >= 85?> --да--> [оценка := 5] --> [конец]
  | нет
  V
<балл >= 70?> --да--> [оценка := 4] --> [конец]
  | нет
  V
<балл >= 50?> --да--> [оценка := 3] --> [конец]
  | нет
  V
[оценка := 2] --> [конец]

Такая «лесенка» из ромбов, спускающихся по ветке нет, называется каскадом условий (по-английски — цепочка if … else if … else). Она проверяет условия сверху вниз и срабатывает на первом истинном.

Перевод каскада в псевдокод

Та же логика в псевдокоде читается почти как блок-схема, только вместо стрелок — слова если / иначе если / иначе:

если балл >= 85 то
    оценка := 5
иначе если балл >= 70 то
    оценка := 4
иначе если балл >= 50 то
    оценка := 3
иначе
    оценка := 2
всё

Обратите внимание: во втором ромбе мы пишем просто балл >= 70, а не 70 <= балл < 85. Верхнюю границу проверять не нужно — если бы балл был 85 и больше, мы бы сюда не дошли: первый ромб увёл бы нас в ветку да. Это и есть главная экономия каскада.

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

Каскад хорош для диапазонов (балл попадает в интервал) и сложных условий. Но бывает другая ситуация: переменная сравнивается с набором конкретных значений — день недели 1, 2, 3 …, код команды, номер месяца. Тогда удобнее множественный выбор — конструкция switch / выбор / case.

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

если месяц = 2 то дней := 28
иначе если месяц = 4 то дней := 30
иначе если месяц = 6 то дней := 30
иначе дней := 31

И множественный выбор:

выбор по месяц
    случай 2:           дней := 28
    случай 4, 6, 9, 11: дней := 30
    иначе:              дней := 31
всё

Второй вариант короче и нагляднее: видно, что мы перебираем именно номер месяца, а ветка случай 4, 6, 9, 11 объединяет четыре значения с одинаковым результатом. На блок-схеме множественный выбор рисуют не цепочкой ромбов, а одним прямоугольником-«переключателем» с несколькими выходами-стрелками по числу веток.

Когда что выбирать

Признак задачиЛучше подходит
Проверяем диапазоны (x < 10, 10 .. 20)каскад если … иначе если
Сложные условия с и/иликаскад
Сравниваем одну переменную с точными значениямимножественный выбор выбор/case
Много веток, по значению можно «прыгнуть» сразумножественный выбор

Как это работает

Под капотом каскад из n условий — это просто n вложенных бинарных проверок: каждая ветка иначе ведёт к следующему сравнению. Поэтому в худшем случае исполнитель сделает все n сравнений (когда истинно последнее или ни одно). А вот множественный выбор транслятор часто превращает в таблицу переходов: по значению переменной он сразу вычисляет адрес нужной ветки, не перебирая остальные. Для школьных задач разница в скорости незаметна, но идея важна: каскад — это «спросить по очереди», выбор — это «сразу попасть куда нужно».

Проверим логику оценок настоящим кодом. Пробежимся по нескольким баллам и посмотрим, какие оценки выставит каскад:

def ocenka(ball):
    if ball >= 85:
        return 5
    elif ball >= 70:
        return 4
    elif ball >= 50:
        return 3
    else:
        return 2

for b in [92, 85, 84, 70, 50, 49, 0]:
    print(b, "->", ocenka(b))

Вывод:

92 -> 5
85 -> 5
84 -> 4
70 -> 4
50 -> 3
49 -> 2
0 -> 2

Видно, что границы 85, 70 и 50 относятся к верхней оценке (знак >= включает само число), а 84 и 49 «проваливаются» в следующую ветку. Это любимое место экзаменационных ловушек: перепутали > и >= — и граничный балл уехал не в ту оценку.

Частые ошибки

  • Дублирование границ в условиях. Писать во втором ромбе 70 <= балл < 85 не ошибка, но лишняя работа: в каскаде верхняя граница уже отсечена. А вот если ветки идут не каскадом (каждый если отдельный, без иначе), то проверять оба конца диапазона обязательно — иначе сработает сразу несколько веток.
  • Неверный порядок условий. Если поставить балл >= 50 первым, то пятёрочник тоже получит тройку — он попадёт в первую же истинную ветку. В каскаде условия идут от самого строгого к самому мягкому.
  • «Висячее» иначе. При ручной вложенности легко привязать иначе не к тому если. Спасают отступы и явный всё (endif), закрывающий каждый блок.
  • Выбор там, где нужны диапазоны. Конструкция case сравнивает с точными значениями, а не с интервалами — для «баллов от 70 до 84» она не годится, нужен каскад.

Итоги

  • Вложенное ветвление — ромб внутри ветки другого ромба; так строят выбор из трёх и более исходов.
  • Каскад если … иначе если … иначе проверяет условия сверху вниз и срабатывает на первом истинном; верхние границы диапазонов отсекаются автоматически.
  • Множественный выбор выбор/case компактнее, когда одна переменная сравнивается с конкретными значениями; на схеме это «переключатель» с несколькими выходами.
  • Диапазоны и сложные условия — каскад; точные значения — выбор. Следите за порядком условий и знаком >= на границах.
Проверьте себя
1. Дан каскад: если балл >= 85 -> 5; иначе если балл >= 70 -> 4; иначе если балл >= 50 -> 3; иначе 2. Какую оценку получит балл = 70?
A5
B4
C3
D2
2. В каком случае множественный выбор (switch/case) удобнее каскада if-else if?
AКогда нужно проверить, попадает ли число в диапазон от 10 до 20
BКогда одна переменная сравнивается с набором конкретных значений (1, 2, 3, ...)
CКогда условие содержит логические И/ИЛИ
DКогда есть всего две ветки: да и нет