Задачник-практикум по основам программирования. Учебное пособие по курсу «Информатика»
.pdf
Контрольные вопросы
1)x = 2 ( ( x2 ) 2 ) 2 = 162 = 256
2)x = 3 ( ( x2 ) 2 ) 2 = 812 = 6561
Пример 8.11. Описать рекурсивную и нерекурсивную функции вы- числения значения по формуле:
1+ 2 + 3 + ... + n
Используя эти функции, вычислить значения для различных n > 3 и сравнить результаты.
program Rec_11; var n:integer;
function f_rec(n,i:integer):real; begin
if i=n then f_rec:=sqrt(n)
else f_rec:=sqrt(i+f_rec(n,i+1))
end;
function f_nrec(n:integer):real; var i:integer;
s:real; begin
s:=0;
for i:=n downto 1 do s:=i+sqrt(s);
f_nrec:=sqrt(s) end;
begin write(‘n=’); readln(n);
writeln(f_rec(n,1)); writeln(f_nrec(n))
end.
Пример 8.12. Описать рекурсивную процедуру построения узора из окружностей по правилам:
151
–окружность первого уровня размещается в середине графического окна (экрана);
–четыре окружности каждого следующего уровня имеют в два раза меньший радиус и их центры располагаются на окружности предыдущего уровня слева, справа, сверху и снизу от ее центра.
Используя эту процедуру, построить узор из окружностей уровня n = 2, 3, 4.
program Rec_12; uses GraphABC;
var x,y,r,n:integer;
procedure Elem(x,y,r,n:integer); begin
if n>0 then begin
Circle(x,y,r); Elem(x-r,y,r div 2,n-1); Elem(x+r,y,r div 2,n-1); Elem(x,y-r,r div 2,n-1); Elem(x,y+r,r div 2,n-1)
end end; begin
x:=WindowWidth div 2; y:=WindowHeight div 2; r:=y div 2;
write(‘Введите число уровней узора ‘); readln(n);
TextOut(250,0,’УЗОР ИЗ ОКРУЖНОСТЕЙ’); Elem(x,y,r,n)
end.
Результат работы программы Rec_12 приведен на рисунке 1.
На рисунке 1 изображены на самом деле не окружности, а круги, т. е. изображения следующего уровня делают невидимыми фигуры пре- дыдущих уровней.
В библиотеке GraphABC предусмотрена возможность рисова- ния «прозрачных» фигур (см. о стилях кисти в справке по PascalABC или в [18]). Для этого в программе Rec_12 перед вызовом процедуры Elem(x,y,r,n)следует добавить обращение к процедуре библиотеки
SetBrushStyle(bsClear);
152
УЗОР ИЗ ОКРУЖНОСТЕЙ
Рис. 1. Узор из окружностей. Число уровней = 3
Тогда будет установлен стиль невидимой кисти, и изображение узора будет «прозрачным», таким как на рисунке 2.
УЗОР ИЗ ОКРУЖНОСТЕЙ
Рис. 2. Узор из окружностей. Использование невидимой кисти
153
Упражнения
1)Модифицировать программу Rec_12 таким образом, чтобы каждая следующая окружность рисовалась другим цветом.
2)Модифицировать программу Rec_12 таким образом, чтобы на каждом уровне окружности рисовались своим цветом.
Пример 8.13. Вводится с клавиатуры посимвольно без ошибок выра- жение. Признак окончания ввода – точка.
Вид выражения определен следующим образом: <выражение>::=<слагаемое> | <слагаемое> ± <слагаемое> <слагаемое>::=<множитель> | <множитель> * <множи-
тель> <множитель>::=<идентификатор> | (<выражение>) <идентификатор>::=<буква>
Преобразовать выражение в постфиксную форму записи. Постфиксная запись (польская инверсная запись – ПОЛИЗ) – бесско-
бочная запись арифметических выражений, при которой знак операции ставится после операндов.
Примеры преобразований:
(A+B)*(C-D) |
→ |
AB+CD-* |
A+B*(C-D) |
→ |
ABCD-*+ |
A+B*C-D |
→ |
ABC*+D- |
Преобразование реализуется с помощью процедур обработки каждой синтаксической конструкции. Так как эти синтаксические конструкции определяются рекурсивно, то соответствующие процедуры взаимно рекур- сивны.
Рекурсивный вызов может быть косвенным. В этом случае процедура обращается к себе опосредованно, путем вызова другой процедуры, в кото- рой содержится обращение к первой.
Согласно правилам языка Паскаль каждый идентификатор перед упот- реблением должен быть описан. Поэтому в случае взаимного обращения подпрограмм (процедур или функций) друг к другу необходимо использо-
вать опережающее описание.
Опережающее описание подпрограммы состоит из ее заголовка, за которым идет зарезервированное слово forward.
program Rec_13;{ Иллюстрация косвенной рекурсии }
procedure Postfix; |
{ |
Преобразование в ПОЛИЗ } |
var ch: char; {хранит |
символ} |
|
154
procedure Find; |
{процедура пропуска пробелов} |
|
begin |
|
|
repeat |
|
|
read(ch) |
|
|
until ch<>’ ‘ |
|
|
end; |
|
{выражение} |
procedure Expression; |
||
var op: char; {знак операции}
procedure Factor; forward; {опережающее описание}
procedure Term; |
{слагаемое} |
begin |
|
Factor; |
|
while ch=’*’ do begin
Find;
Factor;
write(‘*’) {вывод *} end
end; {Term}
procedure Factor; {множитель} begin
if ch=’(‘ then begin
Find;
Expression; end
else
write(ch); {вывод буквы - идентификатора} Find
end; {Factor} begin {Expression}
Term;
while (ch=’+’) or (ch=’-’) do begin
op:=ch;
Find;
Term;
write(op) {вывод знака}
155
end
end; {Expression} begin {Postfix}
Find; write(‘ ‘); repeat
Expression until ch=’.’; writeln
end; {Postfix}
begin {основная программа} Postfix
end.
Упражнения
1)Можно ли поменять описание процедур Factor и Term местами? Необходимо ли при этом использовать опережающее описание?
2)В программе Rec_13 процедуры Factor и Term описаны внутри процедуры Expression. Сделать все три процедуры одного уровня вло- женности в процедуре Postfix.
Пример 8.14. Дано натуральное число n. Получить изображение «ковра Серпинского» n-го порядка [19].
S1 – «Ковер Серпинского» первого порядка.
S2 – «Ковер Серпинского» второго порядка
S3 – «Ковер Серпинского» третьего порядка
156
S4 – «Ковер Серпинского» четвертого порядка
«Ковер Серпинского» или кривая Серпинского i-го порядка [19] об- разуется четырьмя рекурсивными составляющими образами A, B, C, D, которые соединяются линиями, не принадлежащими рекурсивному образу. Эти замыкающие линии представляют собой отрезки прямых в четырех внешних углах. Можно считать, что они принадлежат непустой начальной кривой S0 – квадрату, «стоящему» на одном своем углу.
Составляющая A четвертого порядка
Составляющие A, B, C, D по существу идентичны. Они лишь пово- рачиваются на 90°.
Составляющие A, B, C, D строятся с помощью следующих рекуррен- тных соотношений:
157
S0 : A |
B |
|
C |
D |
. |
Si :для i > 0 |
A, B, C, D строятся следующим образом: |
|
|||
A: A |
B |
→ |
D |
A |
|
B: B |
C |
↓ |
A |
B |
|
C: C |
D |
← |
B |
C |
|
D: D |
A |
↑ |
C |
D |
|
При визуализации рисунка прорисовываются только отрезки в направ- лении, заданном стрелками.
program Rec_14; { Ковер Серпинского } uses GraphABC;
var a, b, x, y, n: integer; procedure lrel (dx,dy: integer); begin
x:=x+dx; y:=y+dy; LineTo(x,y)
end;
procedure BB(k: integer); forward; procedure CC(k: integer); forward; procedure DD(k: integer); forward; procedure AA(k: integer);
begin
if k>0 then begin
AA(k-1); lrel(a,b); BB(k-1); lrel(a,0); DD(k-1); lrel(a,-b); AA(k-1)
end end;
procedure BB(k: integer); begin
if k>0 then begin
BB(k-1); lrel(-a,b); CC(k-1); lrel(0,b); AA(k-1); lrel(a,b);
158
BB(k-1) end
end;
procedure CC(k: integer); begin
if k>0 then begin
CC(k-1); lrel(-a,-b); DD(k-1); lrel(-a,0); BB(k-1); lrel(-a,b); CC(k-1)
end end;
procedure DD(k: integer); begin
if k>0 then begin
DD(k-1); lrel(a,-b); AA(k-1); lrel(0,-b); CC(k-1); lrel(-a,-b); DD(k-1)
end end; begin
n:=6; {порядок кривой} a:=3; b:=a; {длины сторон}
x:=10; y:=10; {координаты начальной точки} SetWindowCaption(‘Ковер Серпинского’); SetWindowSize(590,590);
MoveTo(x,y); AA(N); lrel(a,b); BB(N); lrel(-a,b);
CC(N); lrel(-a,-b); DD(N); lrel(a,-b)
end.
159
Упражнения
1)Получить изображение каждой из составляющих A, B, C, D по отдельности.
2)Модифицировать программу таким образом, чтобы на каждом уровне фрагменты кривых рисовались своим цветом.
3)Можно ли в программе Rec_14 избавиться от опережающего описания процедур аналогично заданию в Упражнении Примера 8.13?
4)Поменять местами описания процедур AA, BB, CC, DD. Настроить программу, чтобы она работала.
ЗАДАЧИ
8.1.Описать рекурсивную функцию C(m, n), где 0 ≤ m ≤ n, для вычисления биномиального коэффициента Cnm по следующей формуле:
Cn0 = Cnn = 1; Cnm = Cnm−1 + Cnm−−11 при 0 < m < n.
8.2.Описать рекурсивную функцию NOD, которая возвращает наибольший общий делитель (НОД) чисел x и y.
НОД для x и y определяется рекурсивно следующим образом [20]:
а)
б)
|
x, |
если y = 0 |
NOD(x, y) = |
|
если y ≠ 0 |
NOD( y, x% y), |
||
где % – операция вычисления остатка от деления нацело;
|
x, |
если x = y |
|
NOD(x − y, y), |
если x > y |
NOD(x, y) = |
||
|
|
если x < y |
NOD(x, y − x), |
||
8.3.Описать рекурсивную функцию root(f, a, b, eps), которая находит приближенное значение корня заданной функции f(x) на отрезке [a, b]
методом деления отрезка пополам (описание метода см. в подразделе Задачи 7.3). Считать, что a < b, f (a) ∙ f (b) <0 и f(x) – непрерывная
и монотонная функция на отрезке [ a,b ].
8.4.Функция f(n) определена для целых положительных чисел следующим образом:
160
