Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
КОМП. НАУКИ_1сем.doc
Скачиваний:
6
Добавлен:
05.11.2018
Размер:
902.14 Кб
Скачать
      1. Итерация и рекурсия. Необоснованное применение рекурсии

Итерация – это организация обработки данных с помощью циклов.

Пример: Вычислим число Фибоначчи с заданным номером с помощью цикла и рекурсивно.

f0=f1=1; fn=fn-1+fn-2 при n>1

function Fib(n:integer):; {Циклический вариант вычисления чисел Фибоначчи}

var i,f1,f2,f3: longint;

begin

if (n=1) or (n=2) then Fib:=1

else begin

f1:=1; f2:=1;

for i:=3 to n do

begin f3:=f1+f2;

f1:=f2; f2:=f3

end

Fib:=f3

end;

end;

function RF(n:integer):longint; {Рекурсивный вариант вычисления чисел Фибоначчи}

begin

if (n=1) or (n=2) then RF:=1

else RF:=RF(n-1)+RF(n-2)

end;

Вычислим рекурсивно 5-ое число Фибоначчи.

Сколько рекурсивных вызовов произойдет?

Для вычисления 4-го числа надо вычислить 3-ое и 2-е, для вычисления 3-го – 2-ое и 1-ое, затем повторно вычислить 2-ое; наконец, повторно вычислить 3-е, 2-ое и 1-ое.

Каждый вызов при n>1 приводит к двум дальнейшим вызовам, т.е. число вызовов растет экспоненциально.

Всего будет 8 рекурсивных вызовов. Кроме того, заново вычисляются числа Фибоначчи, которые уже были вычислены.

Вывод: рекурсивная программа вычисления чисел Фибоначчи непригодна для практического использования.

      1. Глубокая рекурсия

Если алгоритм достигает слишком большой глубины рекурсии, он может привести к переполнению стека.

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

Если стек все равно переполняется, перепишите алгоритм в нерекурсивном виде.

    1. Когда использовать рекурсию

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

Но даже если задача определена рекурсивно, не всегда лучшим способом решения задачи является рекурсивный алгоритм. Во многих случаях вместо краткого рекурсивного алгоритма лучше воспользоваться более простой конструкцией – циклом. Хотя программа станет немного длиннее, работать она будет быстрее.

    1. Формы рекурсивных подпрограмм

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

Рассмотрим четыре разные формы рекурсивных подпрограмм на примере процедур (для функций аналогично):

  1. Действия выполняются до рекурсивного вызова (на рекурсивном спуске).

procedure P; begin S; //выполняется на рекурсивном спуске if условие then Р end;

  1. Действия выполняются после рекурсивного вызова (на рекурсивном возврате).

procedure P; begin if условие then P; S; //выполняется на рекурсивном возврате end;

  1. Действия выполняются до и после рекурсивного вызова (на рекурсивном спуске и на рекурсивном возврате).

procedure P; begin S1; //выполняется на рекурсивном спуске; if условие then P;

S2; //выполняется на рекурсивном возврате end;

или

procedure P; begin if условие then

begin S1; //выполняется на рекурсивном спуске P; S2 //выполняется на рекурсивном возврате end

end.

  1. Каскадная рекурсия – рекурсивные вызовы образуют дерево, например, при рекурсивном вычислении чисел Фибоначчи, при обходе деревьев.

procedure P(n); begin S; //может отсутствовать if условие1 then P(n-1); S1; //может отсутствовать if условие2 then P(n-1); S2 //может отсутствовать

end;