
pascal_lections
.pdfProcedure MasOutput(m,n:Tind; A:TMas); Var i,j:Tind;
Begin Writeln;
writeln('итоговый массив :'); for I:=1 to m do
begin
for j:=1 to n do Write(A[i,j]:3); WriteLn;
End;{for i} End;{procedure}
{переменные программы}
VAR
m,n,Imin :TInd; B :Tmas;
{программа}
BEGIN MasInput(m,n,B);
PoiskMin(m,n,B,Imin);
Smena(m,n,B,Imin);
MasOutput(m,n,B);
readln;
END.
Подпрограммы. Функции
Функция – подпрограмма, у которой произвольное количество входов и ровно один выход, причем в отличие от процедуры имя функции выполняет дополнительную нагрузку – оно совпадает с именем выходного параметра.
Поэтому тело функции должно содержать хотя бы один оператор присваивания имени функции какого-либо значения или выражения.
Структура функции имеет вид:
function Имя(список_формальных_параметров) :тип_результата;
label |
описание локальных меток, |
const |
констант, типов и переменных |
type |
|
var |
|
procedure |
описание внутренних |
function |
процедур и функций |
begin |
|
... |
|
end; |
|
У функции помимо основного выходного параметра, по имени совпадающего с именем функции, могут быть и дополнительные выходные параметры, в качестве которых выступают параметрыпеременные. Их применение и описание аналогично описанию параметров-переменных для процедур.
Пример. Поиск максимального элемента одномерного массива.
21
PROGRAM MaxElem;
Uses crt;
Const RAZ=10;
Type
TInd=1..RAZ;
TMas=array [TInd] of integer;
Procedure MasOutput(m:integer); begin
writeln(‘максимальный элемент равен ’, m); end;
Function MasInput(var A:TMas) :TInd; Var I,N:TInd;
begin
write(‘введите размер массива : ’); readln(N);
writeln;
randomize;
for I:=1 to N do begin
A[I]:=random(100);
Write(A[I]:4);
end;
writeln;
MasInput:=N; {размерность массива} end;
Function PoiskMaxElem(A:TMas; N:TInd) :integer;
Var I:TInd; MaxEl:integer;
Begin
MaxEl:=A[1];
For I:=2 to N do
If A[I]>MaxEl then MaxEl:=A[I];
PoiskMaxElem:=MaxEl;
End;
VAR
N:TInd; A:TMas; Z:integer;
BEGIN
N:=MasInput(A); {размерность массива N, и сам массив А}
Z:=PoiskMaxElem(A,N);
MasOutput(Z);
END.
Параметры процедур и функций.
Открытые параметры-массивы
В заголовках процедур открытые параметры-массивы описываются следующим образом:
Procedure ProcName (Mas :array of MasType);
Передаваемые фактические параметры должны по типу совпадать с описанным типом MasType, но по размерности они могут быть различными: как простой переменной типа MasType, так и массивом любой длины.
22
При этом все открытые параметры-массивы имеют нулевую базу, то есть диапазон изменения индекса фактического массива будет лежать в пределах от 0 до N-1, где N – общее число элементов массива.
Для определения характеристик переданного фактического массива в теле процедуры используются функции:
Low – возвращает индекс первого элемента массива (0), High – возвращает индекс последнего эле-та массива (N-1), SizeOf – возвращает фактический размер массива (N).
Пример.
Сортировка вектор-массивов различной длины.
Program Sort;
Uses crt;
Const
M = 10;
N = 15;
Type
Tvector1 = array [1..M] of integer;
Tvector2 = array [1..N] of integer;
Var
Vector1 :Tvector1;
Vector2 :Tvector2;
Procedure VectorSort( var vector :array of integer );
Var
S, I, J :integer;
Begin
For I:=0 to High(vector)-2 do
For J:=0 to High(Vector)-I-1 do
If Vector[J]<Vector[J+1] then
Begin
S:=Vector[J];
Vector[J]:=Vector[J+1];
Vector[J+1]:=S;
End;
End;
Procedure VectorInput(var Vector :array of integer); Var I:integer;
Begin ClrScr;
Writeln(‘введите ’, High(vector)+1,
‘ элементов типа integer :’); for I:=0 to High(vector) do
begin
write(‘элемент ’,(I+1):3,’ : ’); readln(vector[I]);
end;
writeln;
end;
Procedure VectorOutput(var vector :array of integer);
Var I:integer;
Begin
Writeln(‘результат :’);
For I:=0 to High(vector) do write(Vector[I]:4);
Writeln;
Readln;
End;
BEGIN
VectorInput(vector1);
VectorSort(vector1);
23
VectorOutput(vector1);
{==}
VectorInput(vector2);
VectorSort(vector2);
VectorOutput(vector2);
END.
Рекурсия и опережающее описание.
Вызов процедуры или функции может находиться в любом месте программы, где эта процедура или функция видна, то есть с момента ее описания и до конца составного оператора раздела программы, где это описание присутствует. Следовательно, вызов процедуры или функции может быть внутри тела самой процедуры или функции.
Получается, так называемая, рекурсия – вызов подпрограммой самой себя.
Рекурсия бывает прямой и косвенной.
Прямая рекурсия – подпрограмма вызывает саму себя из собственного набора операторов. Косвенная рекурсия – подпрограмма содержит вызов другой подпрограммы, которая в
свою очередь содержит вызов данной подпрограммы.
Для того чтобы использовать косвенную рекурсию необходимо использовать опережающее описание.
Опережающее описание представляет собой заголовок процедуры, список параметров, (тип возвращаемого значения – для функции) и ключевое слово FORWARD.
Описание самой процедуры (ее тело) представляет собой только заголовок, без списка параметров.
Пример опережающего описания
Program recurs;
Uses crt;
{опережающее описание}
Procedure Rec1(i: integer); forward;
Procedure Rec2(i: integer);
Begin
Writeln(‘рекурсия’);
Rec1(i);
End;
Procedure Rec1;
Begin
If i>0 then
Begin
Writeln(‘взаимная ’);
Rec2(i-1);
End;
End;
BEGIN
Clrscr;
Rec1(3);
END.
Результат работы программы: Взаимная рекурсия Взаимная рекурсия Взаимная рекурсия
24
Рекурсия
Выполнение рекурсивных процедур требует значительно бОльшего размера оперативной памяти во время выполнения, чем не рекурсивных. При каждом рекурсивном вызове для локальных переменных и всех параметров процедуры выделяются новые ячейки памяти. То есть: какой-либо локальной переменной на разных уровнях рекурсии будут соответствовать различные ячейки памяти, которые могут иметь разные значения. Поэтому: воспользоваться значением переменной какого-либо уровня рекурсии можно только на этом уроне!
Глубина рекурсии – максимальное число рекурсивных вызовов процедуры.
Текущий уровень рекурсии – это число рекурсивных вызовов в текущий момент времени.
В общем случае любая рекурсивная процедура Rec включает в себя некоторое множество операторов S и один или несколько операторов рекурсивного вызова P.
Формы рекурсивных процедур.
1. форма с выполнением действий до рекурсивного вызова (рекурсивный спуск)
procedure Rec; begin
S;
if условие then Rec; end;
2. форма с выполнением действий после рекурсивного вызова (рекурсивный возврат)
procedure Rec; begin
if условие then Rec; S;
end;
3. форма с выполнением действий до и после рекурсивного вызова (рекурсивный спуск и возврат)
procedure Rec; begin
S1;
if условие then Rec; S2;
end;
или
procedure Rec; begin
if условие then begin
S1;
Rec;
S2;
end;
end;
При любых формах рекурсии необходимо использовать некоторое условие, которое прекратит цикл рекурсивных вызовов.
25

Выполнение действий на рекурсивном спуске
Вычисление факториала числа N
Program factorial_down;
Var N :integer;
Function fact_down(fact:longint; I,M:integer) :longint; Begin
{накопление факториала} fact:=fact*I;
{рекурсивный вызов}
if I=M then fact_down:=fact
else fact_down:=fact_down(fact,I+1,M); End;
BEGIN
Write(‘Input N: ‘);
Readln(N);
Writeln(‘Factorial N! = ‘, fact_down(1,1,N));
END.
N=5. N!=5!=120
Текущий |
Рекурсивный спуск |
|
|
Рекурсивный возврат |
|
уровень |
|
|
|
|
|
рекурсии |
|
|
|
|
|
0 |
Ввод (N=5) |
|
Fact_down(1,1,5); |
Вывод: N!=120 |
|
1 |
Fact:=1*1 (1) |
|
I=1 |
Fact_down(1,2,5); |
Fact_down:=120; |
2 |
Fact:=1*2 (2) |
|
I=2 |
Fact_down(2,3,5); |
Fact_down:=120; |
3 |
Fact:=2*3 (6) |
|
I=3 |
Fact_down(6,4,5); |
Fact_down:=120; |
4 |
Fact:=6*4 (24) |
|
I=4 |
Fact_down(24,5,5); |
Fact_down:=120; |
5 |
Fact:=24*5 (120) |
|
I=5 |
Fact_down:=120; |
Fact_down:=120; |
Выполнение действий на рекурсивном возврате
Вычисление факториала числа N
Program factorial_up;
Var N :integer;
Function fact_up(I:integer) :longint; Var fact:longint;
Begin
{рекурсивный вызов} if I=1 then fact:=1
else fact:=fact_up(I-1);
{накопление факториала} fact_up:=fact*I;
end;
BEGIN
Write(‘Input N: ’);
Readln(N);
Writeln(‘Factorial N! = ‘, fact_up(N));
END.
26

N=5. N!=5!=120
Текущий |
Рекурсивный спуск |
Рекурсивный возврат |
||
уровень |
|
|
|
|
рекурсии |
|
|
|
|
0 |
Ввод (N=5); |
Fact_up(5) |
Вывод: N!=120 |
|
1 |
I=5 |
Fact:=fact_up(4); |
Fact_up:= 24*5 (120) |
|
2 |
I=4 |
Fact:=fact_up(3); |
Fact_up:= 6*4 |
(24) |
3 |
I=3 |
Fact:=fact_up(2); |
Fact_up:= 2*3 |
(6) |
4 |
I=2 |
Fact:=fact_up(1); |
Fact_up:= 1*2 |
(2) |
5 |
I=1 |
Fact:=1 |
Fact_up:= 1*1 |
(1) |
Выполнение действий на рекурсивном спуске и возврате
Вывести на печать символы введенной строки в обратном порядке
EOLN – функция, возвращает TRUE если строка закончилась…
program reverse_string;
procedure reverse; var ch :char; begin
if not eoln then begin
read(ch);
reverse;
write(ch);
end;
end;
BEGIN
writeln('type any string :'); reverse;
END.
Входная строка ‘HELLO’:
Текущий |
Рекурсивный спуск |
|
Рекурсивный |
|
уровень |
|
|
|
возврат |
рекурсии |
|
|
|
|
0 |
Reverse; |
|
|
|
1 |
EOLN=False; |
input: H; |
Reverse; |
Output: H; |
2 |
EOLN=False; |
input: E; |
Reverse; |
Output: E; |
3 |
EOLN=False; |
input: L; |
Reverse; |
Output: L; |
4 |
EOLN=False; |
input: L; |
Reverse; |
Output: L; |
5 |
EOLN=False; |
input: O; |
Reverse; |
Output: O; |
6 |
EOLN=True; |
|
|
|
27
Пример 1. Вычислить значение целой степени N числа X. 1. без использования рекурсии
A X N X X X X ...X
N раз
function power(X:real; N:integer) :real; var I:integer; A:real;
begin A:=1;
For I:=1 to N do A:=A*X; Power:=A;
end;
2. с использованием рекурсии (рекурсивный возврат)
A X N X X N 1 X X X N 2 ... X X X X ...X 1
function power(X:real; N:integer) :real; begin
if N=0 then power:=1
else power:=X*power(X,N-1); end;
Пример 2. Вычисление факториала
1. без использования рекурсии
B N!1 2 3 4 ...N
function fact(N:integer) :integer; var I,B :integer;
begin B:=1;
For I:=2 to N do B:=B*I; Fact:=B;
end;
2. с использованием рекурсии (рекурсивный возврат)
B N! N (N 1)! N (N 1) (N 2)! ... |
N(N 1)(N 2)...1function fact(N:integer) |
:integer; |
|
begin |
|
if N=0 then fact:=1 |
|
else fact:=N*fact(N-1); |
|
end; |
|
Пример 3. Вычисление значения биномиального коэффициента
C m |
n! |
fact(n) div fact(m) div fact(n-m) |
|
|
|
||
|
|
||
n |
m! (n m)! |
|
|
|
|
28
Рекурсия и опережающее описание.
Пример «Ханойские Башни»
(Ханой – древняя столица Вьетнама)
Для игры используется платформа, на которой укреплены три стержня. На стержни насаживаются диски различного диаметра. Изначально все диски установлены на левом стержне по возрастанию диаметра снизу-вверх, то есть внизу самый большой диск, сверху – самый маленький. Цель игры – перенести башню из дисков с левого стержня на правый. За один раз можно переносить только один диск. И при этом можно насаживать только диск с мЕньшим диаметром на диск с бОльшим диаметром.
program hanoy_tower_2; uses tpcrt;
var K: integer;
{ n - число дисков |
на |
стержне |
Source |
} |
|||
{ Source |
- исходный стержень |
|
} |
||||
{ |
Dest |
- |
стержень, |
на |
который |
нужно переставить диски } |
|
{ |
Temp |
- |
вспомогательный стержень (рабочий) |
} |
|||
procedure MoveDisk(n:integer; |
Source, Dest, Temp :char); |
begin
if n=1 then
WriteLn('переставить диск 1 со стержня ', Source, ' на стержень ',Dest)
else begin
{переставляем n-1 верхних дисков с исходного стержня на вспомогательный, используя целевой стержень в качестве промежуточного}
MoveDisk(n-1,Source,Temp,Dest);
WriteLn('переставить диск ',n:2,' со стержня ', Source, ' на стержень ',Dest);
{переставляем все n-1 дисков со вспомогательного стержня на целевой стержень, используя исходный стержень в качестве промежуточного}
MoveDisk(n-1,Temp,Dest,Source); end;
end;
BEGIN clrscr;
writeln('Ханойские Башни'); write('введите число дисков : '); readln(K);
writeln('решение :'); MoveDisk(K,'A','C','B'); readln;
END.
29

D 1
D 2
D 3
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
D |
2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
D |
3 |
|
|
|
|
|
|
|
|
D |
1 |
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
D |
3 |
|
|
D |
2 |
|
|
|
D |
1 |
|
|
|
|||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
D |
1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
D |
3 |
|
|
D |
2 |
|
|
|
|
|
|
|
|
|||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
D |
1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
D |
2 |
|
|
|
D |
3 |
|
|||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
D |
1 |
|
|
|
D |
2 |
|
|
|
D |
3 |
|
||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
D |
2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||
|
|
|
D |
1 |
|
|
|
|
|
|
|
|
|
D |
3 |
|
|||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
D |
1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
D |
2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
D |
3 |
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
|
A |
|
|
B |
C |
30