рефераты конспекты курсовые дипломные лекции шпоры

Реферат Курсовая Конспект

Рекурсия

Рекурсия - раздел Информатика, Содержание Рекурсия . . . . . . . . . . . . . . . . . . . . . . . . . . 2 ...

Содержание Рекурсия . . . . . . . . . . . . . . . . . . . . . . . . . . 2 Пример 1 . . . . . . . . . . . . . . . . . . . . . . . . . . 2 Пример 2 . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Пример 3 . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Пример 4 . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Пример 5 . . . . . . . . . . . . . . . . . . . . . . . . . . 6 Рекурсия. Рекурсией называется ситуация, когда процедура или функция сама себя вызывает.

Вот типичная конструкция такого рода: procedure proc(i:integer); begin anweisungen1; if bedingung then proc(i+1); anweisungen2; end; Вызов proc(1) означает, что proc вызывает себя раз за разом с помощью proc(2), proc(3) до тех пор, пока условие bedingung не отменит новый вызов. При каждом вызове выполняется оператор anweisungen 1, после чего порядок выполнения операторов прерывается новым вызовом proc(i+1). Чтобы для каждого вызова был отработан и оператор anweisungen2, все локальные переменные процедуры сохраняются в стеке.

Стеком является структура магазинного типа LIFO (Last In First Out), т.е. если, например, при proc(10) условие более не выполняется, anweisungen2 выполняется со значениями, обрабатываемыми в обратном порядке для proc(9),…,proc(1). Локальные параметры помещаются в стек один за другим и выбираются из стека в обратной последовательности (латинское recurrere означает «возвращение назад»). В Паскале можно пользоваться именами лишь тогда, когда в тексте программы этому предшествует их описание.

Рекурсия является единственным исключением из этого правила.Имя proc можно использовать сразу же, не закончив его описания. Пример1 представляет собой бесконечную рекурсию, с помощью которой можно установить, насколько велик стек. При этом помните, что при использовании директивы (*$S+*) при переполнении стека получим сообщение об ошибке; а при использовании директивы (*$S-*) – нет, а значит, мы скорее всего столкнемся с зависанием системы.

Установкой по умолчанию является (*$S+*). Программа будет прервана с выдачей сообщения об ошибке «Error 202: stack overflow error (“Ошибка 202: переполнение стека»). Пример1: Program stack_test; {программа проверки стека} procedure proc(i:integer); begin if i mod 1024 = 0 then writeln(i:6); proc(i+1); end; begin proc(1); end. Стек связан с другой структурой памяти – с динамической областью.С помощью директивы (*$М*) можно управлять размером стека.

Рекурсия не должна восприниматься как некий программистский трюк. Это скорее некий принцип, метод. Если в программе нужно выполнить что-то повторно, можно действовать двумя способами: - с помощью последовательного присоединения (или итерации в форме цикла); - с помощью вложения одной операции в другую (а именно, рекурсий). В следующем примере2 один раз счет от 1 до n ведется с помощью цикла, а второй – с помощью рекурсии.При этом хорошо видно, как заполняется, а затем освобождается стек. В процедуре rekursion операция writeln(i:30) выполняется перед рекурсивным вызовом, после чего writeln(i:3) освобождает стек. Поскольку рекурсия выполняется от n до 1, вывод по команде writeln(i:30) выполняется в обратной последовательности n,n-1,…,1, а вывод по команде writeln(i:3) – в прямой последовательности 1,2,…,n (согласно принципу LIFO – последним пришел, первым обслужен). Пример2: Показывает принципиальное различие между итерацией и рекурсией: итерации необходим цикл и локальная переменная k как переменная цикла.

Рекурсии ничего этого не требуется! program iterativ_zu_rekursion; var n:integer; procedure rekursion (i:integer); begin writeln(i:30); if i < 1 then rekursion(i-1); writeln(i:3); end; (* Рекурсия *) procedure schleife(i:integer); var k:integer; bagin k :=1; while k <= i do begin write(k:3); k :=k+1; end; end; (* Цикл *) begin write(‘Введите n:’); readln(n); writeln(‘Пока:’); scheife(n); writeln; writeln(‘Рекурсия’); rekursion(n); end. Пример3: Рекурсивная процедура convert переводит десятичное число z в восьмеричную систему путем деления его на 8 и выдачи остатка в обратной последовательности.

Program dezimal_oktal_konvertierung; {преобразование из десятичной системы в восьмеричную} var z:integer; procedure convert(z:integer); begin if z > 1 then convert(z div 8); (* Это рекурсивный вызов *) write(z mod 8:1); end; begin writeln(‘Введите некоторое положительное число: ’); readln(z); writeln(‘Десятичное число:’,z:6); write(‘Восьмеричное число: ’); convert(z); end. Один из наиболее ярких примеров применения рекурсии дают числа Фибоначчи.

Они определяются следующим образом: x[1]=x[2]=1 x[n]=x[n-1]+x[n-2] при n > 2 Каждый элемент ряда Фибоначчи является суммой двух предшествующих элементов, т.е. 1 1 2 3 5 8 13 21 34 55 … Следующий пример позволяет вычислить n-ный элемент ряда Фибоначчи как итеративно (то есть в цикле, начиная с х[1] до х[n]), так и рекурсивно (n-ный элемент ряда является суммой двух предшествующих элементов). Причем рекурсивная функция вызывает себя дважды.

Пример4: С использованием рекурсии вычисляются числа Фибоначчи, причем глубина рекурсии индицируется.

Перед каждым рекурсивным вызовом выводится выводиться ASCII-символ с номером 8 (Backspace), а после вызова вновь стирается.Тем самым можно наблюдать за работой программы, поскольку программа за счет delay(300) приостанавливается на 0.3 с. program fibonacci(input, output); 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; end; fibit :=c; end; end; begin clrscr; write(‘n = ‘); readln(n); writeln(‘Итеративно:’,fibit(n):5); writeln(‘рекурсивно:’); write(‘ … ….#… ….#….’); writeln(‘!….#… ….#… ….#’); write (‘Глубина рекурсии:’); 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); Итерация требует меньше места в памяти и машинного времени, чем рекурсия, которой необходимы затраты на управление стеком.

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

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

С таким типом рекурсии мы сталкиваемся там, где использована директива forward. Пример 5: Следующая программа выдает простые числа от 1 до n, для чего используются функции next и prim, которые вызываются перекрестно, то есть рекурсивно.Одновременно это является примером применения директивы forward. program primzahlen_rekursiv_berechnen; {программа рекурсивного вычисления простых чисел} var n,i : integer; c : char; function next(i:integer):integer;forward; {Это прямая ссылка вперед на функцию next, которая будет определена позже} function prim(j:integer):boolean; {prim имеет значение true, если j простое число, и false в противном случае} var k:integer; begin k :=2; while (k*k <= j) and (j mod k < > 0) do k :=next(k); {k пробегает последовательность простых чисел, начиная с 2, вплоть до корня из j, при этом проверяется, делится ли j на одно из таких простых чисел.

При этом используется следующая функция next} if j mod k = 0 then prim := false else prim := true; end {prim}; function next; {Параметры уже стоят в ссылке вперед, next вычисляет, каково следующее за j простое число} var i:integer; begin 1 :=i+1; while not(prim(1)) do 1 :=1+1; {Итак, next вызывает в свою очередь prim} next :=1; end {next}; begin (* Исполняемая часть программы *) write(‘Введите положительное число n,’); writeln(‘Должны быть определены все’); writeln(‘предшествующие ему простые числа’); readln(n); for i :=2 to n do begin if prim(i) then writeln(i:14) else writeln(i:4); if i mod 23 = 0 then begin write(‘<RET>’:60); read(c,c); end; end; end.

– Конец работы –

Используемые теги: Рекурсия0.039

Если Вам нужно дополнительный материал на эту тему, или Вы не нашли то, что искали, рекомендуем воспользоваться поиском по нашей базе работ: Рекурсия

Что будем делать с полученным материалом:

Если этот материал оказался полезным для Вас, Вы можете сохранить его на свою страничку в социальных сетях:

Еще рефераты, курсовые, дипломные работы на эту тему:

Косвенная рекурсия
Рекурсия... Формы рекурсивных процедур... Рекурсивный спуск...

0.024
Хотите получать на электронную почту самые свежие новости?
Education Insider Sample
Подпишитесь на Нашу рассылку
Наша политика приватности обеспечивает 100% безопасность и анонимность Ваших E-Mail
Реклама
Соответствующий теме материал
  • Похожее
  • По категориям
  • По работам