C.Ю.Соловьев

Методические материалы
по курсу
"Алгоритмы и алгоритмические языки"

Программа курса
Программирование в машинных кодах
Примеры-1
Примеры-2
Пример "большой" программы
Нисходящее программирование
Ссылочные типы
Структуры данных
Очереди и стеки
Деревья поиска
AVL-деревья
Таблицы
Хеш-таблицы
Динамические страницы

Примеры. Часть 1

(*                             Пример использования массива *)
(* Программа, которая:                                      *)
(* -1- запрашивает у пользователя коэффициенты полинома;    *)
(* -2- вычисляет значения полинома для заданных аргументов. *)
(*                                                          *)
(* Полином степени n задается коэффициентами                *)
(* A[0], A[1], ..., A[n]  <= по убыванию степеней от n до 0 *)

program BRAIN;
 
Label 999;
Const MXA = 20;                       (* Max степень полинома *)
Type  Coef = array [0..MXA] of real;
 
Var   I,N : integer;
      R,X : real;
        Y : char;
        A : Coef;
 
begin   write('Степень полинома =');
        Readln(N);
        if (N < 1) or (MXA < N) then begin
           writeln('Не могу');
           goto 999
        end;
 
        for I:=0 to N do begin            (* Ввод коэффициентов *)
           write(I:2,'-й коэффициент =');
           Readln(A[I])
        end;
 
        repeat                            (* Вычисления *)
           writeln;
           write(' Аргумент =');
           Readln(X);
           R:=0.;                         (* ;;;;;; Схема ;;;;;; *)
           for I:=0 to N do R:=R*X+A[I];  (* ;;;;; Горнера ;;;;; *)
           writeln('Результат =',R:16:4);
           write('Продолжать ');
           Readln(Y);
        until (Y = 'N') or (Y = 'n');
999: end.
(*                               Пример использования строк *)
(* Программа, которая:                                      *)
(* -1- запрашивает у пользователя даты в формате YYMMDD;    *)
(* -2- сортирует даты;                                      *)
(* -3- выводит (на экран) упорядоченную послед-ть дат       *)
 
program DATE;
 
Label  999;
Const  MXA = 20;
Type   DaType = packed array [1..6] of char;
 
Var   I,J,N,R : integer;
           DT : array [1..MXA] of DaType;
            Y : DaType;
 
begin   write('Количество дат =');
        Readln(N);
        if (N < 1) or (MXA < N) then begin
           writeln('Не могу');
           goto 999
        end;
 
        for I:=1 to N do begin       (* Ввод дат *)
           write(I:2,'-я дата =');
           for J:=1 to 6 do Read(DT[I,J]);
           Readln
        end;
 
        for I:=1 to N-1 do begin     (* Сортировка *)
           R:=I;
           for J:=I+1 to N do
           if DT[J] < DT[R] then R:=J;  {<== Сравнение строк *)
           Y:=DT[R];                    (* ;;;;;Поменять;;;;; *)
              DT[R]:=DT[I];             (* ;;;;;местами;;;;;; *)
                     DT[I]:=Y           (* ;;DT[R] и DT[I];;; *)
        end;
 
        writeln('Результат');
        for I:=1 to N do  writeln(I:2,'. ',DT[I]);
999: end.
(*                                    Пример процедуры No.1 *)
(* Процедура, которая:                                      *)
(* преобразует дату в формате YYMMDD в формат DD-MM-20YY    *)
(*                                                          *)
(* Считаем, что типы alfa06 и alfa12 определены заранее.    *)
(*    type alfa06 = packed array [1.. 6] of char;           *)
(*         alfa10 = packed array [1..10] of char;           *)
 
procedure RECO(var FD : alfa06; var TD : alfa10);
begin   TD:='dd-mm-20yy';
        TD[1]:=FD[5];  TD[ 2]:=FD[6];  (* dd *)
        TD[4]:=FD[3];  TD[ 5]:=FD[4];  (* mm *)
        TD[9]:=FD[1];  TD[10]:=FD[2];  (* yy *)
end;
(*                                    Пример процедуры No.2 *)
(* SortInt : Программа сортировки целых чисел.              *)
(* Считаем, что:                                            *)
(* Целое число ::= последовательность цифр, в которой       *)
(*               - первым знаком могут быть '+' или '-'     *)
(*               - правым ограничителем является '.'        *)
(* Примеры целых: nnn. | +nnnnnn. | -nn. и т.д.             *)
 
program SortInt;
 
Label 999;
Const MAXY =20;
Type  MACC = array [1..MAXY] of integer;
 
var I,J,M,N : integer;
          F : MACC;
          W : boolean;
(* InpInt : принимает из входного потока (с клавиатуры)          *)        
(*          последовательность знаков и преобразует ее в целое V.*)        
(*          Если последовательность не удовлетворяет соглашению  *)        
(*          о представлении целых чисел, то P = false            *)
procedure InpInt(var V : integer; var P : boolean);
 var A,Z : char;
     N,K : integer;
begin  N:=0;          (* Количество прочитанных знаков *)
       K:=0;          (* Количество прочитанных цифр   *)
       Z:='+';        (* Первый знак числа             *)
       V:=0;
       P:=true;       (* Посл.знаков есть целое число  *)
       repeat
          Read(A);
          N:=N+1;
               if ( A  ='+') and (N  =  1 ) then
          else if ( A  ='-') and (N  =  1 ) then Z:='-'
          else if ('0' <= A) and (A <= '9') then begin
                  K:=K+1;
                  V:=10*V+ord(A)-ord('0')
               end
          else if ( A = '.') and (0  <  K ) then
          else                                   P:=false;
       until (A = '.') or (not P);
       Readln;                                   (* Enter *)
       P:=P and (1 <= K);
       if Z = '-' then V:=-V
end;
 
begin   write('Количество целых =');
        InpInt(N,W);                (* Первое использование InpInt *)
        if (not W) or (N < 1) or (MAXY < N) then begin
           writeln('Ошибка ввода.');
           goto 999
        end;
        for I:=1 to N do begin
           write(I:3,'-е число =');
           InpInt(F[I],W);          (* Второе использование InpInt *)
           if not W then begin
              writeln('Неправильное число.');
              goto 999
           end
        end;
     (* Сортировка *)
        for I:=1 to N-1 do begin
           M:=I;
           for J:=I+1 to N do
           if F[J] < F[M] then M:=J;
           J:=F[M];
              F[M]:=F[I];
                    F[I]:=J
        end;
                         writeln('Результат:');
        for I:=1 to N do writeln(I:3,'-е число =',F[I]);
999: end.
 
(* Протокол:      MS-DOS>InpInt<Enter>
                  Количество целых = 4.<Enter>
                    1-е число =8.<Enter>
                    2-е число =-6.<Enter>
                    3-е число =199.<Enter>
                    4-е число =50.<Enter>
                  Результат:
                    1-е число =-6
                    2-е число =8
                    3-е число =50
                    4-е число =199
Конец протокола. *)
(* Побочный эффект - действия, определенные в процедуре или функции, *)
(*                             которые:                              *)
(*                   - либо изменяют глобальные переменные;          *)
(*                   - либо производят ввод/вывод и т.п.             *)
 
program EFF;
 
var A,B : real;        (* Глобальные переменные *)
 
function FCX(X : real) : real;
    var A1 : real;
begin   A:=0.7*X+0.6;  (* Изменение глобальных переменных *)
        FCX:=A*X+0.3
end;
 
begin   A:=1.;
        B:=FCX(1.0);
        writeln(A:10:2, B:10:2);
                       (* A = 1.30 <== Результат побочного эффекта *)
                       (* B = 1.60 *)
end.
(*                            Пример рекурсивной процедуры Rsin  *)
(*          вычисления значения sin(X) по заданному аргументу X. *)
(*                                                               *)
(* Подход: sin(X) = X при малых X  /первый замечательный предел/ *)
(*         sin(X) = 2*sin(X/2)*(1-2*sqr(sin(X/2))) иначе         *)
(*                                 /тригонометрическое тождество/*)

program ReqSin;
 
var X,Yr,Ys : real; 
          I : integer;
 
function Rsin(X : real) : real;
begin   if   abs(X) < 0.0001
        then Rsin:=X
        else Rsin:=2*Rsin(X/2)*(1 - 2*sqr(Rsin(X/4)))   end;
 
begin   writeln('X':5,'sin(X)':13,'Rsin(X)':15,'Погрешность':16);
        X:=0;
        for I:=1 to 20 do begin
           Yr:=Rsin(X);
           Ys:= sin(X);
           writeln(X:7:3,Ys:14:9,Yr:14:9,abs(Ys-Yr):14:9);
           X:=X+0.35;
        end
end.
(* Протокол:      MS-DOS>ReqSin                              
                     X       sin(X)        Rsin(X)     Погрешность   
                   0.000   0.000000000   0.000000000   0.000000000   
                   0.350   0.342897807   0.342897808   0.000000000   
                   0.700   0.644217687   0.644217688   0.000000001   
                   1.050   0.867423226   0.867423226   0.000000000   
                   1.400   0.985449730   0.985449730   0.000000000   
                   1.750   0.983985947   0.983985947   0.000000000   
                   2.100   0.863209367   0.863209366   0.000000001   
                   2.450   0.637764702   0.637764700   0.000000002   
                   2.800   0.334988150   0.334988147   0.000000003   
                   3.150  -0.008407247  -0.008407252   0.000000005   
                   3.500  -0.350783228  -0.350783229   0.000000002   
                   3.850  -0.650625137  -0.650625139   0.000000002   
                   4.200  -0.871575772  -0.871575774   0.000000001   
                   4.550  -0.986843859  -0.986843859   0.000000001   
                   4.900  -0.982452613  -0.982452612   0.000000001   
                   5.250  -0.858934493  -0.858934491   0.000000003   
                   5.600  -0.631266638  -0.631266633   0.000000005   
                   5.950  -0.327054815  -0.327054807   0.000000008   
                   6.300   0.016813900   0.016813910   0.000000010    
                   6.650   0.358643853   0.358643856   0.000000003   
Конец протокола. *)
(*                          Усовершенствованная функция Rsin *)
(*  Недостаток функции Rsin состоит в том, что для каждого   *)
(*  фиксированного  аргумента (большего 0.0002)  Rsin(X/4)   *)
(*  вычисляется дважды:                                      *)
(*  - cначала как Rsin(X/2) половинного аргумента, а         *)
(*  - затем   как Rsin(X/4) полного     аргумента.           *)
(*                                                           *)
(*  Для устранения этого недостатка введем процедуру  Csin,  *)
(*  которая по заданному аргументу X (рекурсивно) вычисляет  *)
(*  Y = sin(X) и Y2 = sin(X/2).                              *)
 
procedure Csin(var Y,Y2 : real; X : real);
   var Y4 : real;                            (*  Y4 = sin(X/4) *)
begin   if abs(X) <= 0.0001 then begin
           Y:=X;
           Y2:=X/2
        end                 else begin
           Csin(Y2,Y4,X/2);
           Y:=2*Y2*(1-2*sqr(Y4))
        end                           end;
 
(* С помощью Csin функция Rsin определяется просто.          *)
 
function Rsin(X : real) : real;
   var Y,Y2 : real;
begin   Csin(Y,Y2,X);
        Rsin:=Y            end;
(*                             Пример рекурсивной процедуры *)
(* IncOne : К положительному двоичному числу D длины N      *)
(*          прибавить единицу.                              *)
(* Подход:                                                  *)
(* Если N = 0,                                              *)
(* то         IncOne('') = '1',                             *)
(* иначе либо IncOne('d...d0') = 'd...d1',                  *)
(*       либо IncOne('d...d1') = IncOne('d...d')+'0' { рек }*)
(*                                                          *)
 
program TEST14;
 
type alfa10 = packed array [1..10] of char;
 var   X : alfa10;
       N : integer;
 
procedure IncOne(var D : alfa10; var N : integer);
begin        if   N  =  0  then begin N:=1; D[N]:='1' end
        else if D[N] = '0' then             D[N]:='1'
        else begin
           N:=N-1;
           IncOne(D,N); (* рекурсивный вызов *)
           N:=N+1;
           D[N]:='0'
        end
end;
 
begin   (* Пример обращения к IncOne *)
        X:='10111     '; N:=5;
        IncOne(X,N);
        writeln('Результат = ',X);
end.
 
(* Протокол:      MS-DOS>TEST14<Enter>
                  Результат = 11000
Конец протокола. *)
 
(*               Пример рекурсивной процедуры (продолжение) *)
(* Как работает IncOne ?                                    *)
(*                   Trace - процедура (отладочной) печати  *)
(*                           двоичного числа D длины N      *)
 
program TEST14m;
 
type alfa10 = packed array [1..10] of char;
 var   X : alfa10;
       N : integer;
 
procedure Trace(var D : alfa10; N : integer);
   var I : integer;
begin   write('  Длина=',N,'  Строка=''');
        for I:=1 to N do write(D[I]);
        writeln('''')                   end;
 
procedure IncOne(var D : alfa10; var N : integer);
begin   write('Вход IncOne');
        Trace(D,N);
             if   N  =  0  then begin N:=1; D[N]:='1' end
        else if D[N] = '0' then             D[N]:='1'
        else begin
           N:=N-1;
           IncOne(D,N); (* рекурсивный вызов *)
           N:=N+1;
           D[N]:='0'
        end;
        write('Exit IncOne');
        Trace(D,N);
end;
 
begin   (* Пример обращения к IncOne *)
        X:='10111     '; N:=5;
        IncOne(X,N);
        writeln('Результат = ',X);
end.
 
(* Протокол:      MS-DOS>TEST14m<Enter>
                  Вход IncOne  Длина=5  Строка='10111'
                  Вход IncOne  Длина=4  Строка='1011'
                  Вход IncOne  Длина=3  Строка='101'
                  Вход IncOne  Длина=2  Строка='10'
                  Exit IncOne  Длина=2  Строка='11'
                  Exit IncOne  Длина=3  Строка='110'
                  Exit IncOne  Длина=4  Строка='1100'
                  Exit IncOne  Длина=5  Строка='11000'
                  Результат = 11000
Конец протокола. *)
(*                                              Факультативно. *)
(* IntSeq : процедура, которая преобразует (символьную) строку *)
(*          входных данных в массив целых чисел ISQ[1..N]   из *)
(*          диапазона [-9999..+9999].                          *)
(*          Считается, что число задается последовательность   *)
(*          цифр (со знаком).                                  *)
(*          Правой границей числа являются:                    *)
(*          - конец строки (eoln)      ; или                   *)
(*          - символ, отличный от цифры; или                   *)
(*          - цифра, если ее появление в числе приводит к      *)
(*            выходу за пределы диапазона [-9999..+9999].      *)
(* Примеры: 10;20;-17;66  ISQ[1..4] = 10, 20, -17 и 66         *)
(*          31 -54 -54    ISQ[1..3] = 31, -54 и -54            *)
(*          4444444444    ISQ[1..3] = 4444, 4444 и 44          *)
(* Полагаем, что предельный размер массива задается константой *)
(*           MSQ. Если во входном потоке содержится более  MSQ *)
(*           чисел, то числа с номерами > MSQ игнорируются.    *)
 
const  MSQ = 200;
var    ISQ : array [1..MSQ] of integer;
 
procedure IntSeq(var N : integer);
   var K,R,Z : integer;
           A : char;
   procedure BISQ;
   begin   N:=N+1;
           if (N <= MSQ) and (0 < K) then ISQ[N]:=R
                                     else N:=N-1;   (* Откат *)
           K:=0; R:=0; Z:=1;
   end;
begin      K:=0; R:=0; Z:=1;
        N:=0;
        while not eoln do begin
           Read(A);
           if ('0' <= A) and (A <= '9') then begin
              R:=10*R+Z*(ord(A)-ord('0'));
              K:=K+1;
              if 1000 <= abs(R) then BISQ
           end                          else BISQ;
           if A = '-' then Z:=-1
        end;
        BISQ;
        Readln                                 end;
 
(*                              Конец факультативного примера. *)

Вопросы?