Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекция 6 Итерация и рекурсия.doc
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
348.16 Кб
Скачать

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

Классическим примером рекурсивной функции является вычисление факториала. Из курса математики известно, что , . С другой стороны .

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

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

Таким образом, рекурсивная подпрограмма будет иметь вид:

function Factorial (n:byte):longint; begin

if (n=0) or (n=1) {описываются условия граничных случаев}

then Factorial:=1 {точка возврата или остановка рекурсии} else Factorial:= Factorial (n-1)*n; { шаг рекурсии }

end;

Или так

function Factorial (n:byte):longint; begin

if n>0 then Factorial:= Factorial (n-1)*n; { шаг рекурсии }

else Factorial:=1 {точка возврата или остановка рекурсии} end;

На рисунке 16.2 показан процесс вычисления для случая Factorial(4).

Первый вызов функции осуществляется из основной программы, например a:= Factorial(4). Он продолжается до тех пор, пока значение локальной переменной не становится равной 1. После этого начинается выход из рекурсии. В результате вычислений получается, что Factorial(4)=4*3*2*1.

Сначала образуется так называемый рекурсивный фрейм №1 при n=4. Для этого фрейма отводится память и в нем фиксируются все значения переменных тела функции при n=4. Отметим, что в рекурсивном фрейме фиксируются значения всех переменных функции, кроме глобальных.

Рис. 16.2. Вычисление функции Factorial(n) для n=4.

Затем происходит вызов Factorial(n) при n=3. Образуется фрейм №2, где фиксируются значения переменных тела функции при n=3. При этом фрейм №1 также хранится в памяти. Из фрейма №2 происходит обращение к Factorial(n) при n=2. В результате этого обращения образуется фрейм №3, где фиксируются значения переменных тела функции при n=2 и т.д. до тех пор, пока при очередном обращении к функции Factorial условие n>0 не примет значение false.

Это произойдет в фрейме №5. В этом фрейме мы получим значение Factorial =1 и передадим это значение в фрейм №4. После этого фрейм №5 будет уничтожен, так как обращение Factorial(n) при n=0 будет выполнено.

В фрейме №4 мы вычислим значение Factorial(n) для n=1. После чего мы передадим это значение во фрейм №3, а фрейм №4 будет закрыт, так как обращение к Factorial(n) при n=1 будет закончено.

Так мы будем сворачивать эту цепочку фреймов в последовательности, обратной той, в которой мы их порождали, пока не свернем фрейм №1. После чего вычисление функции будет окончено.

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

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

Существует два важных положения, известных в математике и в программировании, определяющих соотношение между итерацией и рекурсией:

- Любой итеративный цикл может быть заменен рекурсией.

- Рекурсия не всегда может быть заменена итерацией.

Большая часть всех шуток о рекурсии касается бесконечной рекурсии, в которой нет условия выхода, например, известно высказывание: «чтобы понять рекурсию, нужно сначала понять рекурсию».

В действительности итерация и рекурсия взаимозаменяемы.

Пример:

function fact (n: integer): longint;

begin

if n=0 then fact:=1

else fact:=n*fact(n-1);

end;

begin

f:=1;

for i:=1 to n do

f:=f*i;

end.

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

Для хранения этой информации используется стековая память, поэтому в данном случае предпочтительнее итерационная форма.

Реализуем вычисление факториала, как в виде функции, так и в виде процедуры на языке Pascal.