Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
MEGAPACK_version_final.doc
Скачиваний:
6
Добавлен:
15.09.2019
Размер:
2.34 Mб
Скачать

45. Використання стеку для організації рекурсивних обчислень.

Функция называется рекурсивной, если в её определении содержится вызов этой же функции. Различают простую рекурсию, когда текст программы функции F напрямую содержит вызов F, и косвенную рекурсию, когда F обращается к иным функциям, которые содержат вызов F.

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

Более ранний рекурсивный вызов всегда закончится позже. Этот факт позволяет применить для управления локальной памятью рекурсивных процедур такую структуру данных как стек. Стек характеризуется следующими свойствами: он имеет неопределенный размер (реально размер ограничен техническими параметрами компьютера); элементы стека не нумеруются, доступен (для чтения) только один элемент, верхний; после удаления из стека верхнего элемента доступным становится следующий и т.д.; вновь помещаемый в стек элемент становится верхним. Таким образом, стек - линейная структура данных, доступная для чтения и записи только с одного конца, т.е. работа со стеком подчиняется дисциплине LIFO (last in - first out, последним включен - первым удален). Стек можно моделировать линейным списком, но это неэффективно по времени, поэтому обычно стек моделируется одномерным массивом и двумя индексными переменными - указателями на дно и на вершину стека. Современные компьютеры поддерживают стеки аппаратно - специальными регистрами-указателями на сегменты памяти, предназначенные для размещения стеков, на вершины стеков и командами для выполнения операций со стеками.

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

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

Рис.1. Изменение содержимого стека при обработке рекурсивных вызовов

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

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]