Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Алгор_ТХТК_пособие.doc
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
1.6 Mб
Скачать

7.3 Формы рекурсий

Простая линейная рекурсия

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

Пример 7.5 Нахождение НОД двух натуральных чисел по алгоритму Евклида. Алгоритм заключается в следующем: если т является точным делителем и, то НОД = т, в противном случае нужно брать функцию НОД от т и от остатка деления п на т.

{Линейная рекурсия } {Алгоритм Евклида}

Function NOD(n, m : byte): byte;

Begin {NOD} if m >n then

NOD := NOD(m,n) {Рекурсивная ветвь }

else

if m = 0 then

NOD := n {Терминальная ветвь }

else

NOD := NOD(m, n mod m) {Рекурсивная ветвь }

End; {NOD}

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

Параллельная рекурсия

Если в описании подпрограммы по меньшей мере в одной рекурсив­ной ветви встречаются два или более рекурсивных вызова, то говорят о нелинейной, или параллельной, рекурсии. Один из наиболее ярких при­меров такой рекурсии дают числа Фибоначчи:

F(0) = 0, F(1) = 1,F(N) = F(N-1) + F(N-2).

Каждый элемент ряда Фибоначчи является суммой двух предшествующих элементов: 1 1 2 3 5 8 13 21 34 55 ...

Пример 7.6 Вычислить n-й член ряда Фибоначчи.

{Параллельная рекурсия. Числа Фибоначчи}

Function fib(n : integer): integer;

Begin {fib}

If n = 0 then

fib := 0 {Терминальная ветвь }

else

if n = 1 then

fib := 1 {Терминальная ветвь }

else

fib := fib(n-1 )+ fib (n-2){Рекурсивная ветвь }

End; {fib}

Для определения текущего значения F(N) функциями вызывает себя дважды в одной и той же рекурсивной ветви - параллельно. Заметим, что параллельность является лишь текстуальной, но никак не временной: вы­числение ветвей в стеке производится последовательно. В отличие от линейной рекурсии, при которой структура рекурсивных вызовов ли­нейна, нелинейная рекурсия ведет к древовидной структуре вызовов. Вы­зовы лавинообразно ведут к экспоненциальному нарастанию возникаю­щих рекурсивных вызовов - «каскаду вызовов», отсюда еще одно назва­ние - каскадная рекурсия.

Взаимная рекурсия

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

Пример 7.7 Программа выдает простые числа от 1 до и, для чего используются функции next и prim, которые вызываются перекрестно.

{Взаимная рекурсия. Простые числа}

Program Primzahlen;

Var

n, i: integer; {Опережающее описание}

Function Next (i: integer): integer;

forward; {Prim определяет: j - простое число или нет}

Function Prim(j : integer): Boolean;

Var

к: integer; Begin {Prim}

k:=2;

while (k*k <= j) and (j mod к <> 0) do

к := Next(k);{Prim вызывает Next}

if j mod к = 0 then

Prim := false

else

Prim := true;

end{Prim};

{Next вычисляет, каково следующее за j простое число. Параметры функции уже стоят в ссылке вперед}

Function Next, Var

k: integer;

Begin {Next}

k := i+l;

while not(Prim(k)) do

k := k+1; {Next вызывает, в свою очередь, Prim}

next := k;

End {Next};

Begin {Primzahlen}

Writeln('Введите положительное число п,');

ReadLn(n);

Writeln('Предшествующие ему простые числа');

for i := 2 to n do