Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Билеты по проге.docx
Скачиваний:
5
Добавлен:
01.07.2025
Размер:
630.61 Кб
Скачать

Характеристики рекурсии

  1. Глубина рекурсии – количество рекурсивных вызовов. О(х^n) n – глубина рекурсии, количество рекурсивных вызовов. Не более 10..100. Дерево рекурсивных вызовов:

Глубина рекурсии – глубина дерева.

Void A(n) { if (n<=r) return; A(n-k); … m -раз A(n-k); } Первый раз вызываем функцию с параметром N0: A(N0). Всего вызовов: 1+m+m2+…m(N0-2)/k= m(N0-r)/k) +1-1. ( в лекции норм. Ф-ла) Пример для головоломки «Ханойские башни»:

Каждая операция увеличивает в 2 раза + 1 кол-во перемещений N0=n, k=1, m=2, r=1. Получаем, что количество всех перестановок равно 2n-1.

Виды рекурсии

  1. Прямая – если функция содержит ссылку на себя.

  2. Косвенная – если функция А содержит ссылку на другую функцию В, которая содержит ссылку на функцию А.

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

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

  1. В точке вызова в стек помещаются параметры, передаваемые функции, и адрес возврата.

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

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

  4. Команда возврата из функции, считывает из стека адрес возврата и выполняет переход по этому адресу. Одновременно стек очищается от параметров.

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