Приёмная комиссия 2024

Рекурсия в Python: что это, как с ней работать и как увеличить ее лимит

Рекурсия в Python: что это, как с ней работать и как увеличить ее лимит
Содержание

Рекурсия в Python — это эффективный инструмент, который позволяет решать сложные задачи, разбивая их на более простые подзадачи. Она находит широкое применение при работе с рекурсивными структурами данных, такими как деревья и графы, а также в алгоритмах «разделяй и властвуй», например в быстрой сортировке и сортировке слиянием.

Подберите программу обучения и начните учиться бесплатно

Оставьте заявку и мы откроем бесплатный доступ к вводной части обучения

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

Что такое рекурсия в Python

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

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

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

  1. Считать шаги один за другим, пока не дойдём до конца.
  2. Спросить себя, сколько шагов до конца, если сделать один шаг, и так далее, пока не окажешься на последней ступеньке.

Принцип работы рекурсии

Рекурсия состоит из двух основных частей:

  1. Базовый случай (base case): Условие, при котором функция прекращает рекурсивные вызовы. Это условие не позволяет функции вызывать саму себя бесконечно
  2. Рекурсивный случай (recursive case): Условие, при котором функция вызывает саму себя.

Пример на Python

Вычислим факториал числа. Факториал числа n — это произведение всех чисел от 1 до n. Например, 4! = 4×3×2×1 = 24

В среде Питона это можно решить следующим образом:

def factorial (n):
if n == 1: # Базовый случай: если число равно 1, то факториал 1
return 1
else:
return n * factorial (n — 1) # Рекурсивный случай: умножаем число на факториал предыдущего числа
print (factorial (n))

Попробуйте вставить и запустить этот код в любом интерпретаторе Python, чтобы проверить, что всё работает корректно.


Как работают рекурсивные функции

Понимание работы с рекурсией можно облегчить, если рассматривать её шаг за шагом. Давайте разберём пошаговый процесс на примере вычисления факториала числа n.

Пример: Вычисление факториала

Формула факториала:

{ n≠1, если n≤1 }
n≠nx (n−1), если n>1

Рекурсивная функция для вычисления факториала:

def factorial (n):
if n <= 1: # Базовый случай
return 1
else:
return n * factorial (n — 1) # Рекурсивный случай

Пошаговый процесс

Допустим, нам нужно вычислить factorial (4).

Шаг 1: Первый вызов функции

  • Входное значение: n = 4
  • Условие: n <= 1 ложное.
  • Выполняется: 4 * factorial (3)

Шаг 2: Второй вызов функции

  • Входное значение: n = 3
  • Условие: n <= 1 ложное.
  • Выполняется: 3 * factorial (2)

Шаг 3: Третий вызов функции

  • Входное значение: n = 2
  • Условие: n <= 1 ложное.
  • Выполняется: 2 * factorial (1)

Шаг 4: Четвёртый вызов функции

  • Входное значение: n = 1
  • Условие: n <= 1 истинное.
  • Возвращается: 1 (так как базовый случай достигнут, и факториал 1 равен 1)

Шаг 5: Возвращение результатов

  • Четвёртый вызов: factorial (1) возвращает 1
  • Третий вызов: 2 * factorial (1) становится 2 * 1 и возвращает 2
  • Второй вызов: 3 * factorial (2) становится 3 * 2 и возвращает 6
  • Первый вызов: 4 * factorial (3) становится 4 * 6 и возвращает 24

Таким образом, factorial (4) возвращает 24.

Основные шаги при работе с рекурсией:

  1. Базовый случай: убедитесь, что у вас есть состояние, при котором рекурсивная функция перестанет вызывать саму себя.
  2. Рекурсивный случай: определите, как задача будет разбиваться на более мелкие подзадачи и как функция будет вызывать саму себя для их решения.
  3. Понимание стека вызовов: разберитесь, как каждый вызов функции помещается в стек вызовов и как возвращаются значения.
  4. Тестирование и отладка: проверьте работу рекурсивной функции на различных значениях, включая базовые (например, n = 0 или n = 1) и крайние случаи (например, большие значения n). Это поможет убедиться, что функция работает корректно и не вызывает переполнение стека.

Как увеличить глубину рекурсии

В Python можно увеличить глубину рекурсии с помощью функции sys.setrecursionlimit. По умолчанию максимальная глубина рекурсии составляет около 1000, но это значение можно изменить. Однако стоит помнить, что увеличение глубины рекурсии может привести к переполнению стека и вызвать RecursionError, особенно если функция вызывает себя большое количество раз.

Вот как это можно сделать:

  1. Импортируйте модуль sys.
  2. Установите новое значение глубины рекурсии с помощью sys.setrecursionlimit.

Пример:

import sys

# Увеличение глубины рекурсии до 3000
sys.setrecursionlimit (3000)

def recursive_function (n):
if n == 0:
return «Done»
else:
return recursive_function (n — 1)
print (recursive_function (2999)) # Это сработает

Важные замечания

  1. Использование с осторожностью: При увеличении глубины рекурсии следует быть осторожным, так как слишком большие значения могут вызвать переполнение стека и привести к сбою программы.
  2. Альтернативные решения: Если вы приближаетесь к пределу глубины рекурсии, рекомендуется рассмотреть альтернативные подходы, такие как итеративные методы или использование явного стека для имитации рекурсивного поведения.
  3. Тестирование и отладка: Всегда проверяйте программу с разными входными данными, чтобы убедиться в её корректности, и следите за производительностью и использованием памяти, особенно при увеличении глубины рекурсии.

Пример альтернативного решения с использованием стека

Если вам нужно обрабатывать очень глубокие рекурсивные вызовы, рассмотрите использование собственного стека:

def iterative_factorial (n):
stack = []
result = 1
while n > 0:
stack. append (n)
n -= 1
while stack:
result *= stack. pop ()
return result
print (iterative_factorial (3000)) # Это сработает для очень больших значений n

Как избежать ошибок при работе с рекурсией

Работа с рекурсивными алгоритмами может быть непростой задачей, особенно если не учесть возможные ошибки и проблемы, которые могут возникнуть. Например, это может быть переполнение стека вызовов или неэффективный алгоритм. Давайте рассмотрим наиболее распространенные ошибки, которые могут возникнуть при работе с рекурсией.

  1. Отсутствие базового случая

    Ошибка: Если рекурсивная функция не имеет базового случая, она будет вызывать саму себя бесконечно, что приведет к переполнению стека (Stack Overflow).

    def factorial (n):
    return n * factorial (n — 1) # Нет базового случая

    Исправление: Добавьте базовый случай, чтобы завершить рекурсию.

    def factorial (n):
    if n <= 1: # Базовый случай
    return 1
    else:
    return n * factorial (n — 1)

  2. Неправильное определение базового случая

    Ошибка: Базовый случай может быть определен неправильно, что приведет к неверным результатам или бесконечной рекурсии. Например, при вычислении факториала базовый случай должен быть n <= 1, а не n == 0, так как 0! и 1! оба равны 1.

    def factorial (n):
    if n == 0: # Ошибочный базовый случай для факториала
    return 0
    else:
    return n * factorial (n — 1)

    Исправление: Убедитесь, что базовый случай правильно определен.

    def factorial (n):
    if n <= 1: # Правильный базовый случай
    return 1
    else:
    return n * factorial (n — 1)

  3. Изменение параметров функции некорректно

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

    def countdown (n):
    print (n)
    countdown (n + 1) # Увеличение n вместо уменьшения

    Исправление: Изменяйте параметры функции правильно.

    def countdown (n):
    if n <= 0: # Базовый случай
    print («Done!»)
    else:
    print (n)
    countdown (n — 1)

  4. Переполнение стека

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

    def fibonacci (n):
    if n <= 1:
    return n
    else:
    return fibonacci (n — 1) + fibonacci (n — 2)

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

    # Использование мемоизации для уменьшения глубины рекурсии
    memo = { }
    def fibonacci (n):
    if n in memo:
    return memo[n]
    if n <= 1:
    return n
    memo[n] = fibonacci (n — 1) + fibonacci (n — 2)
    return memo[n]

  5. Неправильное использование глобальных переменных

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

    counter = 0

    def recursive_function (n):
    global counter
    if n <= 0:
    return counter
    else:
    counter += 1
    return recursive_function (n — 1)

    Исправление: Передавайте необходимые значения как параметры функции.

    def recursive_function (n, counter=0):
    if n <= 0:
    return counter
    else:
    return recursive_function (n — 1, counter + 1)

Как работает хвостовая рекурсия

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

Пример хвостовой рекурсии

Приведем пример вычисления факториала с использованием хвостовой рекурсии:

def factorial (n, accumulator=1):
if n == 0:
return accumulator
else:
return factorial (n — 1, n * accumulator)
print (factorial (5)) # Output: 120

Как работает хвостовая рекурсия

  • Последний вызов: В хвостовой рекурсии последним действием функции является рекурсивный вызов, при этом никакие дополнительные вычисления не происходят после этого вызова.
  • Оптимизация стека: Некоторые компиляторы и интерпретаторы могут оптимизировать хвостовую рекурсию с помощью техники, называемой оптимизацией хвостовых вызовов (tail call optimization). Эта техника позволяет перераспределить текущий стек вызовов для следующего рекурсивного вызова, эффективно заменяя текущий фрейм стека, чтобы избежать его переполнения.

Почему хвостовая рекурсия полезна

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


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

Рекурсия применяется для решения задач, которые можно разделить на более мелкие подзадачи. Это касается работы с рекурсивными структурами данных, такими как деревья и графы. Также рекурсия используется при реализации алгоритмов «разделяй и властвуй», например, при быстрой сортировке или сортировке слиянием. Кроме того, рекурсия помогает в решении рекурсивных математических задач, например, при вычислении факториала или чисел Фибоначчи.

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

  • Факториал числа

Факториал числа n (обозначается n!) равен произведению всех положительных целых чисел от 1 до n. Например, 5! = 5x4x3x2x1 = 120.

def factorial (n):
if n == 0:
return 1
else:
return n * factorial (n — 1)

print (factorial (5)) # Output: 120

  • Числа Фибоначчи

Числа Фибоначчи — это последовательность, в которой каждое число (начиная с третьего) является суммой двух предыдущих. Последовательность начинается с 0 и 1. Например, первые несколько чисел Фибоначчи: 0, 1, 1, 2, 3, 5, 8, 13.

def fibonacci (n):
if n <= 1:
return n
else:
return fibonacci (n — 1) + fibonacci (n — 2)
print (fibonacci (10)) # Output: 55

  • Сумма чисел во вложенном списке

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

def sum_nested_list (lst):
total = 0
for element in lst:
if isinstance (element, list):
total += sum_nested_list (element)
else:
total += element
return total
nested_list = [1, [2, [3, 4], 5], 6]
print (sum_nested_list (nested_list)) # Output: 21

Главное, что нужно знать

  • Рекурсия — это метод программирования, при котором функция вызывает сама себя для решения задачи, разбивая её на более простые подзадачи. Этот подход применяется для задач, которые можно разбить на несколько задач того же типа.
  • Каждый рекурсивный алгоритм должен иметь базовый случай — условие, при котором рекурсия заканчивается. Это предотвращает бесконечный цикл вызовов функции и обеспечивает возвращение результата.
  • Рекурсивный подход разделяет задачу на подзадачи, которые аналогичны исходной задаче, но имеют меньший размер. Это упрощает решение сложных задач, делая их более понятными и управляемыми.
  • Каждый вызов функции помещается в стек вызовов. Глубина рекурсии ограничена размером стека, и если она слишком большая, может произойти переполнение стека (Stack Overflow). Это важно учитывать при проектировании рекурсивных функций.
  • Рекурсия широко используется для решения различных задач, таких как обход деревьев и графов, сортировка и поиск, генерация комбинаторных объектов, решение оптимизационных задач и многих других, которые естественно разбиваются на повторяющиеся подзадачи. Понимание и умение применять рекурсию являются важными навыками для эффективного решения подобных задач.

Подберите программу обучения и начните учиться бесплатно

Оставьте заявку и мы откроем бесплатный доступ к вводной части обучения

alt

Всё для учебы доступно онлайн

Расписание, зачётку и домашние задания смотрите в приложении
Подберите программу обучения

ответьте на пять вопросов и узнайте, где будете учиться

Образование для карьеры
К каким профессиям вы более склонны?
ТехническимГуманитарнымТворческимМедицинским
Какой у вас уровень образования?
Без образованияШкола 9-11 классКолледжБакалавриатМагистратураАспирантура
Какой формат обучения вам подходит?
ОчноЗаочноОнлайнПо выходным дням
Интересует ли вас кредит на образование по ставке 3% в год?
ДаНет

Мы подобрали для вас программу обучения

Заполните форму, чтобы узнать больше о программе и наших предложениях

Подобрать программу и поступить

Политика конфиденциальности

Ваша конфиденциальность очень важна для нас. Мы хотим, чтобы Ваша работа в Интернет по возможности была максимально приятной и полезной, и Вы совершенно спокойно использовали широчайший спектр информации, инструментов и возможностей, которые предлагает Интернет. Персональные данные, собранные при регистрации (или в любое другое время) преимущественно используется для подготовки Продуктов или Услуг в соответствии с Вашими потребностями. Ваша информация не будет передана или продана третьим сторонам. Однако мы можем частично раскрывать личную информацию в особых случаях, описанных в данной Политике конфиденциальности.

Рамки Политики конфиденциальности

Настоящая Политика конфиденциальности (далее — «Политика») применяется к информации, полученной через данный сайт, иные сайты, виджеты и другие используемые интерактивные средства, на которых есть ссылка на данную Политику (далее — «Сайт») от пользователей Сайта (далее — «Пользователи»).

Нижеследующие правила описывают, как Университет «Синергия» обращается с любой информацией, относящейся к прямо или косвенно определенному или определяемому физическому лицу (субъекту персональных данных) (далее — «Персональные данные»), для целей оказания услуг с использованием Сайта.

Пользователи включают в себя всех физических лиц, которые подключаются к Сайту и используют Сайт.

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

Настоящая Политика конфиденциальности вступает в силу с момента ее размещения на Сайте, если иное не предусмотрено новой редакцией Политики конфиденциальности.

Контролирующие и обрабатывающие лица

Пользователи соглашаются с тем, что:

  • Пользуясь Сайтом, и принимая условия использования, опубликованные на Сайте, пользователь заявляет о своем однозначном согласии с обработкой его Персональных данных способами, описанными в настоящей Политике.
  • Обработка Персональных данных Пользователей осуществляется Оператором персональных данных — Университет «Синергия» (ИНН: 7729152149, ОГРН: 1037700232558).

С какой целью собираются эти данные

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

Сбор Персональных данных

При регистрации на Сайте Пользователи подтверждают свое согласие с условиями настоящей Политики и свое согласие на обработку своих Персональных данных в соответствии с условиями настоящей Политики, кроме того они соглашаются на обработку своих Персональных данных на серверах Университета «Синергия», расположенных на территории Российской Федерации.

Обработка Персональных данных осуществляется не дольше, чем этого требуют цели обработки Персональных данных, изложенные в настоящей Политике (за исключением случаев, предусмотренных законодательством Российской Федерации). Университет «Синергия» может обрабатывать следующие Персональные данные:

  • «Как к Вам обращаться» в форме обратной связи, в случае если посетитель указывает свои полные ФИО или только часть;
  • Электронный адрес;
  • Номер телефона;
  • Также на сайте происходит сбор и обработка обезличенных данных о посетителях (в т. ч. файлов «cookie») с помощью сервисов интернет-статистики (Яндекс Метрика и других).
  • Вышеперечисленные данные далее по тексту Политики объединены общим понятием Персональные данные.

Как эти данные используются

На сайте используются куки (Cookies) и данные о посетителях сервисов (Яндекс Метрика и других). При помощи этих данных собирается информация о действиях посетителей на сайте с целью улучшения его содержания, улучшения функциональных возможностей сайта и, как следствие, создания качественного контента и сервисов для посетителей. Вы можете в любой момент изменить настройки своего браузера так, чтобы браузер блокировал все файлы cookie или оповещал об отправке этих файлов. Учтите при этом, что некоторые функции и сервисы не смогут работать должным образом.

Как эти данные защищаются

Для защиты Вашей личной информации мы используем разнообразные административные, управленческие и технические меры безопасности. Наша Компания придерживается различных международных стандартов контроля, направленных на операции с личной информацией, которые включают определенные меры контроля по защите информации, собранной в Интернет. Наших сотрудников обучают понимать и выполнять эти меры контроля, они ознакомлены с нашим Уведомлением о конфиденциальности, нормами и инструкциями. Тем не менее, несмотря на то, что мы стремимся обезопасить Вашу личную информацию, Вы тоже должны принимать меры, чтобы защитить ее. Мы настоятельно рекомендуем Вам принимать все возможные меры предосторожности во время пребывания в Интернете. Организованные нами услуги и веб-сайты предусматривают меры по защите от утечки, несанкционированного использования и изменения информации, которую мы контролируем. Несмотря на то, что мы делаем все возможное, чтобы обеспечить целостность и безопасность своей сети и систем, мы не можем гарантировать, что наши меры безопасности предотвратят незаконный доступ к этой информации хакеров сторонних организаций.

В случае изменения данной политики конфиденциальности вы сможете прочитать об этих изменениях на этой странице или, в особых случаях, получить уведомление на свой e-mail.

Политика в отношении обработки персональных данных.pdf

В случае изменения данной политики конфиденциальности вы сможете прочитать об этих изменениях на этой странице или, в особых случаях, получить уведомление на свой e-mail.

Jivo

DMCA.com Protection Status