{Функция на Pascal}
Function Factorial(N:integer): longint;
Begin
If N<=1
Then Factorial:=1
Else Factorial:=Factorial(N-1)*N
End;
{Процедура на Pascal}
Procedure Factorial(N:integer; Var F:longint);
Begin
If N<=1
Then F:=1
Else Begin Factorial(N-1, F); F:=F*N End
End;
Пример вызова из основной программы:
x:= Fact(a); writeln( a, ‘!= ', x); Factorial(a, F); writeln( a, ' != ', F);
Результат 5!= 120 5!= 120
Пример: Числа Фибоначчи
Известным примером
рекуррентной последовательности
второго порядка является последовательность
чисел Фибоначчи, для которой
,
а для
:
.
Применительно
к рекуррентным последовательностям
часто ставится задача найти
-й
элемент последовательности.
Для решения этой задачи
достаточно хранить в памяти
элемент
последовательности. Решение задачи
разбивается на два основных этапа:
начальную установку и продвижение по
последовательности.
Для вычисления
чисел Фибоначчи первый этап выглядит
следующим образом:
a:=1; b:=1
Продвижение
по последовательности на один элемент
вперед выполняется так:
for k:=3 до
n do
begin
c:=a+b;
a:=b;
b:=c;
end;
Каждый
из элементов последовательности,
начиная с третьего в данном случае, как
бы отбирает значение у следующего
элемента. Последний элемент, после того
как у него отобрали значение, получает
новое путем применения рекуррентной
формулы. Безвозвратно
теряемые старые значения уже не нужны,
поскольку на последующие вычисления
они повлиять не могут.
Составим
алгоритм нахождения n-го числа Фибоначчи
с начала до конца:
program fibonacciITER;
var
n, f, a, b, c, k: integer;
begin
writeln (‘Введите число n');
readln ( n );
a:=1; b:=1;
for k:=3 to n do
begin
c:=a+b;
a:=b;
b:=c
end;
f:=c;
writeln (n, '-й член последовательности Фибоначчи равен ', f); end.
В следующей программе числа Фибоначчи вычисляются вначале с использованием итерации, а затем с использованием рекурсии, причем глубина рекурсии отображается. Перед каждым рекурсивным вызовом команда delay(900) приостанавливает вывод глубины рекурсии на 0.9 с.
program fibonacci;
uses crt;
var n,result:integer;
function fibit(n:integer):integer;
var a,b,c,i:integer;
begin
a := 1; b := 1;
if (n=1) or (n=2)
then fibit :=1
else begin
for i:= 3 to n do
begin c :=a+b; a := b; b :=c; write (c,' '); end;
fibit :=c;
writeln;
end;
end;
function fibrek(n:integer):integer;
begin
if (n=1) or (n=2) then fibrek := 1
else
begin
writeln ('Глубина рекурсии:',n);
delay(900) ;
fibrek := fibrek(n-1)+fibrek(n-2);
end;
end;
begin
clrscr;
write('Какое по счету число Фиббоначчи вывести? ');
readln(n);
writeln('Итеративно:',fibit(n):5);
writeln('Рекурсивно:');
result := fibrek(n);
writeln;
write(result);
end.
Этот пример демонстрирует прежде всего различия между итерацией и рекурсией. Итерации необходим цикл и вспомогательные величины; итерация сравнительно ненаглядна (см. fibit в приведенном выше примере).
Рекурсия обходится без вспомогательных величин и обычно проще для понимания, что демонстрирует следующая запись:
if (n=1) or (n=2) then fibrek := 1
else fibrek := fibrek(n-1)+fibrek(n-2);
Итерация требует меньше места в памяти и машинного времени, чем рекурсия, которой необходимы затраты на управление стеком.
Итак, если для некоторой задачи возможны два решения, предпочтение следует отдать итерации. Правда, для многих задач рекурсивная формулировка совершенно прозрачна, в то время как построение итерации оказывается весьма сложным делом.
Рекурсивный метод решения задач является чуть ли не базовым методом решения алгоритмических задач. Рекурсия, дополненная идеями динамического программирования, жадными алгоритмами и идеей отсечения, превращается в тяжёлую артиллерию программистов. Но не следует забывать, что краткость записи рекурсивных функций не всегда означает высокую скорость их вычисления. И есть ряд задач, в которых рекурсия просто вредна (такова, например, задача вычисления кратчайшего пути в графе).
