РУҚА
Тапсырмалар № 16, 27 · ЕГЭ

Сравнение рекурсии и итерации

Как выбрать рекурсию или цикл для одной и той же тапсырма
6 мин чтенияҚиындық: Обновлено 29 қыркүйек 2026

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

Основные понятия

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

Итерационный алгоритм повторяет действия явно: с помощью цикла for, while или другого управляющего средства. На каждой итерации изменяются переменные состояния, пока не выполнится условие остановки. Подробнее изменение счётчика и границы цикла важно проверять так же, как в теме изменение переменной цикла.

D
Определения

Рекурсия — способ шешімдер, при котором функция обращается к самой себе. Итерация — одно повторение тела цикла; итерационный алгоритм организует повторение без жаңа вложенных вызовов функции. Базовый случай прекращает рекурсивные вызовы.

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

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

Как устроено выполнение

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

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

\[M_{\text{рекурсии}}=O(h),\qquad M_{\text{цикла}}=O(1)\]1

Здесь \(h\) — максимальная глубина рекурсии. Формула справедлива для линейной рекурсии, где каждый вызов создаёт не более одного следующего вызова и не требуется хранить дополнительный массив. Если функция создаёт несколько ветвей или сохраняет результаты, оценка памяти меняется.

ПризнакРекурсивное ШешімИтерационное Шешім
ПовторениеНовые вызовы функцииИтерации цикла
ПамятьСтек вызовов, обычно \(O(h)\)Переменные цикла, часто \(O(1)\)
ЧитаемостьУдобно для деревьев, графов, вложенных структурУдобно для последовательного счёта
Риск ошибкиНет базового случая или глубина слишком великаБесконечный цикл, неверная граница
СкоростьЕсть расходы на вызовыОбычно немного быстрее

Обе версии имеют одинаковый порядок времени, если на каждом шаге выполняют одну и ту же работу. Например, последовательное вычисление факториала занимает \(O(n)\) и при рекурсии, и при цикле; различается главным образом память.

Проверь себя

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

Одна тапсырма в двух вариантах

Рассмотрим вычисление \(n! = 1\cdot2\cdot3\cdot\ldots\cdot n\). Рекурсивное определение естественно записывается так: \(0!=1\), а \(n!=n\cdot(n-1)!\). Циклическая версия последовательно накапливает произведение от \(1\) до \(n\).

Python
1def factorial_recursive(n):
2    if n == 0:
3        return 1
4    return n * factorial_recursive(n - 1)
5
6
7def factorial_iterative(n):
8    result = 1
9    for value in range(2, n + 1):
10        result *= value
11    return result
№
Разобранный пример: факториал 5

Найдём \(5!\) двумя способами. В рекурсивной версии сначала строится цепочка вызовов, а умножение выполняется при возврате. В циклической версии произведение увеличивается сразу на каждой итерации.

1
Записываем рекурсивное разложение до базового случая.
\(\displaystyle 5!=5\cdot4!=5\cdot4\cdot3!=5\cdot4\cdot3\cdot2\cdot1\cdot0!\)
2
Подставляем значение базового случая.
\(\displaystyle 0!=1\Rightarrow 5!=5\cdot4\cdot3\cdot2\cdot1=120\)
3
Повторяем те же умножения в цикле. Начальное значение результата равно единице.
\(\displaystyle r_0=1,\quad r_1=1\cdot2=2,\quad r_2=2\cdot3=6\)
4
Завершаем итерации значением 5.
\(\displaystyle r_3=6\cdot4=24,\quad r_4=24\cdot5=120\)

В обеих программах выполняется төрт умножения для \(n=5\), то есть число действий линейно зависит от \(n\). Рекурсивная версия использует стек глубины 6: вызовы для \(5,4,3,2,1,0\). Циклу достаточно нескольких переменных.

Как переводить рекурсию в цикл

Сначала определите, что изменяется от вызова к вызову. Если рекурсивный вызов просто уменьшает параметр на единицу, часто подходит цикл while немесе for. Если функция возвращает накопленный результат, заведите переменную-накопитель. Если рекурсия идёт по двум направлениям или возвращается к предыдущим состояниям, простой цикл может оказаться недостаточным.

  1. Запишите базовый случай и условие продолжения.
  2. Найдите параметр, который приближается к базовому случаю.
  3. Создайте переменную состояния, соответствующую параметру функции.
  4. Создайте накопитель результата, если значения перемножаются, складываются или объединяются.
  5. Проверьте начальное значение и границы цикла на малых случаях: \(0\), \(1\), \(2\).

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

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

Когда какой способ выбирать

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

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

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

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

1. Путают число рекурсивных вызовов с числом умножений: базовый вызов тоже занимает место в стеке, но не выполняет переход. 2. В цикле ставят границу range(1, n), забывая включить \(n\). 3. При переводе рекурсии теряют начальное значение результата: для произведения это \(1\), для суммы — \(0\). 4. Считают рекурсию всегда более медленной или всегда более сложной: всё зависит от структуры алгоритма. 5. Не проверяют случай \(n=0\) и получают неверный ответ или бесконечный цикл.

Приём для экзамена

Составьте таблицу состояний: номер шага, значения параметров и текущий результат. Для рекурсии запишите сначала спуск к базовому случаю, затем подъём; для цикла — строки после каждой итерации. Такой способ помогает не перепутать порядок вычислений.

Быстрая проверка

Q
Жылдам тест по теме

Проверьте понимание

~ 2 мин4 вопроса
Вопрос 1 / 4
Вопрос 1 из 4 · память
Какова дополнительная память линейной рекурсии глубины \(n\) без оптимизации?
Главное за минуту

Главное

  • Рекурсия повторяет вычисление через вызовы функции, а итерация — через цикл.
  • У корректной рекурсии есть базовый случай и переход к нему; без них выполнение не завершится.
  • Линейная рекурсия и соответствующий цикл часто имеют одинаковое время \(O(n)\), но рекурсия обычно требует \(O(n)\) памяти против \(O(1)\) у цикла.
  • Для перевода рекурсии в цикл нужно сохранить параметры, состояние и накопитель результата.
  • Рекурсия удобна для деревьев, графов и вложенных структур, цикл — для последовательного счёта и ограниченного числа повторений.