Рекурсия
Подпрограмма называется рекурсивной, если она вызывает саму себя (прямая рекурсия). Рекурсивной будет также п/программа, вызывающая другую п/подпрограмму, которая в свою очередь обращается к первой п/программе (косвенная рекурсия). Возможны и более сложные конструкции.
Количество рекурсивных вызовов называется глубиной рекурсии. Глубина рекурсии должна быть конечной, т.е. чтобы процесс обращения подпрограммы к самой себе не был бесконечным, устанавливают барьер в виде некоторого условия для обеспечения остановки.
“Правила предосторожности” при написании рекурсивных программ:
Рекомендуется компилировать программу с директивой {$S+}, которая включает проверку переполнения стека (области памяти, в которой хранится состояние вызывающей подпрограммы), а так же использовать директиву {$R+} проверки диапазона переменных (тогда если будет переполнение стека, программа завершится и на экране появится сообщение об ошибке).
в начале процедуры (функции), вызываемой рекурсивно, можно разместить строку if keypressed then Halt. В этом случае при зависании программы вместо перезагрузки будет достаточно нажать на любую клавишу.
Недостаток рекурсивных подпрограмм – это большой расход памяти. Поэтому, где это возможно, следует избегать рекурсии и заменять ее итерационными вычислениями (т.е. в цикле).
Пример. Вычисление факториала.
n!=1*2*…*n=n*(n-1)!,
0!=1
1 способ.
Function Fact(n:integer):longint;
begin
if n=1 then Fact:=1 {n=1-барьер}
else Fact:=n*Fact(n-1)
end;
2 способ.
F:=1;
for i:=1 to n do
F:=F*i
Пример. Вывести n-е число последовательности Фибоначчи
1,1,2,3,5,8,13,…
a1,a2,a3,…
ai= 1, i=1,2
ai-1+ai-2, i>2
1 способ.(рекурсивный)
Function F(n:integer):longint;
begin
if keypressed then Halt;
if ((n=1) or (n=2)) then F:=1 {барьер}
else F:=F(n-2)+F(n-1);
end;
2 способ.
Function G(n:integer):longint;
var x,y,t: longint;
i:integer;
begin
x:=1; y:=1;
for i:=3 to n do
begin
t:=y;{t- дополнительная переменная для хранения}
y:=x+y;
x:=t;
end;
G:=y;
end;
Упражн. Вычисление целой степени вещественного числа.
y=ax, a<>0
Задача “Ханойская башня”
Классическая задача, использующая рекурсивный алгоритм (связана с легендой, по которой монахи ханойского храма строили башню).
На площадке A находится пирамида из дисков, уменьшающихся от основания к вершине. Эту пирамиду в том же виде нужно перенести на площадку В, используя площадку С, как вспомогательную. При этом:
перекладывать можно только по одному диску;
класть диск можно только на диск с большим диаметром или на основание площадки.
A (исходный) В (конечный) С (промежуточный)
Пусть n – количество дисков.
n=2: A→C; A→B; C→B – всего 3 хода.
n=3: A→B; A→C; B→C; A→B; C→A; C→B; A→B
– всего 7 ходов.
Составим программу, по которой будет рассчитан алгоритм работы монахов для любого значения n.
Алгоритм задачи следующий:
если n=0, то ничего не делать.
если n>0, то 1 шаг: переместить (n-1) диск на С через В
2 шаг: переместить 1 нижний диск с А на В
3 шаг: переместить (n-1) диск с С на В через А
Program bashnja;
var n:integer;
procedure Hanoi (n:integer; A,B,C:char);
begin
if n>0 then {барьер}
begin
Hanoi (n-1, A,C,B); {1 шаг}
writeln(A, ‘=>’,B); {2 шаг}
Hanoi (n-1, C,B,A); {3 шаг}
end;
end;
begin {основная программа}
writeln (‘введите n’);
readln (n);
Hanoi (n,A,B,C);
end.
Рекурсия в графике
Рекурсивные алгоритмы используются при рисовании фрактальных кривых. Фрактал – это самоподобный объект, т.е. такой объект, у которого любая меньшая часть похожа на целый объект.
П
ример.
Треугольник Серпинского
