Лабораторная работа Язык программирования Паскаль Тема: Рекурсивные алгоритмы Порядок выполнения работы 1. Изучить теоретические сведения по теме “Рекурсивные алгоритмы ”. 2. Получить индивидуальное задание у преподавателя и разработать программу в соответствии с поставленной задачей. 3. Показать работающую программу преподавателю. 4. Ответить на контрольные вопросы. 5. Подготовить письменный отчет. Форма представления отчета: 1. Тема работы. 2. Условия задания. 3. Текст программы и исходные данные при вводе. 4. Результаты выполнения программы. Краткие теоретические сведения. Алгоритм называется рекурсивным, если он прямо или косвенно обращается к самому себе. Часто в основе такого алгоритма лежит рекурсивное определение какого-то понятия. Например, вычисление факториала можно определить следующим образом: еслиN 1, тоN! 1 N! = еслиN 1, тоN! N * ( N 1)! Рекурсивный алгоритм обращается к самому себе, пока не выполнится определенное условие, поэтому в любой рекурсивной подпрограмме должна быть нерекурсивная ветвь (в примере 1 это: if N=1 then Fact:=1). Примером программы с использованием рекурсии может быть программа вычисления факториала числа. Пример1. Вычисление факториала числа N с использованием рекурсивной функции program Demo_Rekurs; var N : integer; F : longint; {Описание функции, N — формальный параметр-значение типа integer, результат выполнения функции типа longint}. function Fakt(N : integer): longint; begin {Начало вычисления функции} if N=1 then Fakt:=1 {Проверка условия завершения рекурсии} else Fakt:=N*Fakt(N-1); {Рекурсивное вычисление N!} end; begin {Начало главной программы} Writeln('Введите число N : ') ; Read(N) ; F:=Fakt(N); {Вызов функции для фактического параметра N} Writeln('Для числа',N,'значение факториала= ', F); end. После запуска программы на экран выводится запрос: "Введите число N: ", затем с клавиатуры считывается значение целого числа N и в выражении F:=Fakt(N) вызывается функция Fakt с параметром-значением N. В подпрограмме-функции вычисления факториала проверяется условие N=1. Если оно выполняется, то функции Fakt присваивается значение 1, на этом выполнение подпрограммы-функции завершается. Если условие N=1 не соблюдается, то выполняется вычисление произведения N*Fakt(N-1). Вычисление произведения носит рекурсивный характер, так как при этом осуществляется вызов функции Fakt(N-1), значение которой вычисляется, в свою очередь, через вызов функции Fakt, параметром которой также будет функция Fakt, и т. д., до тех пор, пока значение формального параметра N=1. Так как базовая часть описания рекурсивной функции Fakt определяет значение Fakt для N=1, равным единице, то рекурсивные вызовы функции Fakt больше не выполняются, а наоборот, выполняется вычисление функции Fakt для чисел, возрастающих от 1 до N, причем функция Fakt всякий раз возвращает значение, равное произведению очередного k-гo числа на факториал от k-1-го числа. Последнее возвращение результата вычисления функции Fakt присвоит переменной F значение произведения всех чисел от 1 до N, т. е. факториал числа N. Вывод. При выполнении рекурсивной подпрограммы осуществляется многократный переход от некоторого текущего уровня организации алгоритма к нижнему уровню последовательно до тех пор, пока, наконец, не будет получено тривиальное решение поставленной задачи. В рассмотренном выше примере решение при N=1 тривиально, т.е. Fakt=1. Затем осуществляется возврат на верхний уровень с последовательным вычислением значения функции Fakt. Следует учитывать, что использование рекурсивной формы организации алгоритма обычно выглядит изящнее итерационной и дает более компактный текст программы, но при выполнении, как правило, медленнее и может вызвать переполнение стека. Это объясняется тем, что при каждом входе в подпрограмму ее локальные переменные размещаются в особым образом организованной области памяти, называемой программным стеком. Пример 2. Расчет суммы первых N натуральных чисел Вычисление суммы 1+2+3+…+N можно определить следующим образом: еслиN 0, тоSum 0 Sum(N) = еслиN 0, тоSum N Sum( N 1) Program Pr2; Var N: integer; Function Sum(N: integer): integer; begin if N=0 then Sum:=0 else Sum:= N+Sum(N-1); end; BEGIN {основная программа} Write('N='); Readln(N); Writeln('S=', Sum(N)); Readln END. Пример 3. Вычисление n-го члена последовательности Фибоначчи. Последовательность Фибоначчи определяется следующим образом: первые два числа равны 1, а каждое следующее равно сумме двух предыдущих (1, 1, 2, 3, 5,…). Вычисление n-го члена последовательности Фибоначчи можно определить следующим образом: еслиN 1илиN 2, тоFib : 1 Fib(n)= еслиN 2, тоFib : Fib(n - 1) Fib(n - 2) Program Pr3; Var n:integer; Function Fib(n:integer):integer; begin if n<=2 then Fib:=1 else Fib:=Fib(n-1)+Fib(n-2); end; BEGIN {основная программа} Write('n='); Readln(n); Write(Fib(n):5); Readln END. Пример 4. Расчет n-члена арифметической прогрессии, заданной значением первого члена a1 и разностью d. Вычисление n-члена арифметической прогрессии можно определить следующим образом: еслиN 1, тоan a1 еслиN 1, тоan a n 1 d an = Program Pr4; Var n:integer; d,a1:real; Function Arifm(a1,d:real; n:integer):real; begin if n=1 then Arifm:=a1 else Arifm:=Arifm(a1,d,n-1) + d; end; BEGIN {основная программа} Write('a1='); Readln(a1); Write('d='); Readln(d); Write('n='); Readln(n); Write(Arifm(a1,d, n):5:2); Readln END. Пример 5. Нахождения суммы n членов арифметической прогрессии, заданной значениями первого члена прогрессии а и разности d. Program Pr5; Var s,a,n,d: integer; Function sa(n,a,d:integer):integer; begin if n>0 then sa:=a+ sa(n-1,a+d,d) else sa:=0; end; BEGIN {основная программа} Write('n='); Readln(n); Write('a='); Readln(a); Write('d='); Readln(d); Write(sa(n,a,d)); Readln END. Пример 6. Возведение числа a в целую степень n. Program Pr6; Var a:real; n:integer; Function Stepen(a: real;n:integer):real; begin if n=0 then Stepen:=1 else if n>0 then Stepen:=a*Stepen(a,n-1) else Stepen:=(1/a)*Stepen(a,n+1); end; BEGIN {основная программа} Write('a='); Readln(a); Write('n='); Readln(n); Write(Stepen(a,n):6:4); Readln END. Пример 7. Представление натурального числа в двоичной системе счисления. Program Pr7; Var n:integer; Procedure Bin_n(n:integer); begin if n>1 then Bin_n(n div 2); Write( n mod 2) end; BEGIN {основная программа} Write('n='); Readln(n); Bin_n(n); Readln END. Пример 8. Нахождения наибольшего общего делителя двух натуральных чисел Program Pr8; Var a,b:integer; Function Nod(a,b:integer):integer; begin if a=b then Nod:=a else if a>b then Nod:=Nod(a-b, b) else Nod:=Nod(a, b-a) ; end; BEGIN {основная программа} Write('a='); Readln(a); Write('b='); Readln(b); Writeln('NOD(', a, ',', b, ')=', Nod(a,b)); Readln END. Контрольные вопросы 1. Определение рекурсивного алгоритма. 2. Какое условие должно обязательно присутствовать в любой рекурсивной процедуре? 3. Где размещаются локальные переменные при рекурсивном вызове процедуры? 4. Пример программы с использованием рекурсии. Задания для самостоятельной работы 1. Вычислить (a! + b!)/a!, используя рекурсивную функцию вычисления факториала 2. Вычислить m!/(m + n)!, используя рекурсивную функцию вычисления факториала 3. Вычислить (1+2+3+4+5)/( 1+2+3+4+5+6+7+8), используя рекурсивную функцию вычисления суммы первых n натуральных чисел. 4. Составить рекурсивную функцию для вычисления S = 2 + 4 + 6 +…+2*n 5. Составить рекурсивную функцию для вычисления S = 5 + 10 + 15 +…+5*n 6. Составить рекурсивную функцию для вычисления P = 2* 4* 6*…*2*n 7. Составить рекурсивную функцию вычисления n-го члена арифметической прогрессии 3, 7, … и вывести первые 10 членов прогрессии . 8. Составить рекурсивную функцию вычисления n-го члена геометрической 1, 2, … и вывести первые 8 членов прогрессии . 9. Составить рекурсивную функцию вычисления n-го члена последовательности: а1= 1, ai = ai-1*i. Найти сумму 2-го и 5-го членов последовательности. 10. Составить рекурсивную функцию вычисления n-го члена последовательности: а1= 0, ai = 2*ai-1+i. Найти произведение 3-го и 7-го членов последовательности. 11. Составить рекурсивную функцию нахождения суммы n членов арифметической прогрессии 1, 3, …Найти сумму с 5-го по 10-й членов прогрессии 12. Составить рекурсивную процедуру, которая печатает введенное натуральное число в восьмеричном представлении 13. Найти наибольший общий делитель для чисел A, B, C, используя рекурсивную функцию нахождения наибольшего общего делителя двух натуральных чисел 14. Сократить дробь a/b (a, b – введенные натуральные числа), используя рекурсивную функцию нахождения наибольшего общего делителя двух натуральных чисел 15. Составить рекурсивную функцию вычисления суммы цифр произвольного натурального числа. 16. Составить рекурсивную функцию вычисления среднего арифметического цифр произвольного натурального числа. 17. Вычислить (42 + 23)/2-2 , используя рекурсивную функцию возведения в степень 18. Вычислить (53 - 33)/2-1 , используя рекурсивную функцию возведения в степень 19. Составить рекурсивную функцию, которая вычисляет среднее арифметическое элементов одномерного массива. 20. Найти первые N чисел Фибоначчи двумя способами: с помощью рекурсии и с помощью итерации. Сравнить эффективность алгоритмов. 21. Составить рекурсивную функцию для вычисления суммы элементов одномерного массива. 22. Составить рекурсивный алгоритм нахождения максимального элемента одномерного массива 23. Составить рекурсивный алгоритм нахождения минимального элемента одномерного массива 24. Ханойские башни. Имеется три стержня А, В, С. На стержень А нанизано п дисков в порядке уменьшения их радиусов (Самый большой внизу, самый маленький – сверху). Требуется переместить все диски на стержень В, сохраняя их порядок расположения (диск с большим радиусом находится ниже). За один раз можно перемещать только один диск с любого стержня на любой другой стержень и нельзя больший диск класть на меньший.