Алгоритмические языки высокого уровня. Курс лекций
.pdfСортировка методом прямого включения
Сортировка методом прямого включения, так же, как и сортиров- ка методом простого выбора, обычно применяется для массивов, не содержащих повторяющихся элементов.
Сортировка методом прямого включения, как и все описанные выше, производится по шагам. На k-м шаге считается, что часть массива, содержащая первые k – 1 элементов, уже упорядочена, т.е.
а[1] < = a [2]< = … < = a[k-1].
Далее необходимо взять k-й элемент и подобрать для него та- кое место в отсортированной части массива, чтобы после его вставки упорядоченность не нарушилась, т.е. надо найти такое
j (1 < = j < = k-1), что a[j] < = a[k]<a[j+1].
Затем надо вставить элемент a[k] на найденное место.
С каждым шагом отсортированная часть массива увеличивается. Для выполнения полной сортировки потребуется выполнить n-1 шаг.
Пример программы
Описание: сортировка методом прямого включения.
Program sorting3; var
n,x,j,k:integer;
a: array [1..50] of integer;
begin
writeln('введите размер массива'); readln(n);
for j:=1 to n do read(a[j]); for k:=2 to n do
begin x:=a[k]; j:=k-1;
while (j>0) and (x<=a[j]) do begin
a[j+1]:=a[j]; dec(j); {j:=j-1}
end;
a[j+1]:=x;
end;
writeln;
for j:=1 to n do write(a[j]:5);
end.
71
4.2.2. Записи
Запись представляет собой совокупность ограниченного числа ло- гически связанных компонент, принадлежащих к разным типам. Компоненты записи называются полями, каждое из которых опреде- ляется именем. Поле записи содержит имя поля, вслед за которым через двоеточие указывается тип этого поля. Поля записи могут от- носиться к любому типу, допустимому в языке Pascal, за исключени- ем файлового типа.
Описание записи в языке Pascal осуществляется с помощью слу- жебного слова record, вслед за которым описываются компоненты записи. Завершается описание записи служебным словом end.
Например, телефонный справочник содержит фамилии и номера телефонов, поэтому отдельную строку в таком справочнике удобно представить в виде следующей записи:
type
TRec = Record FIO: String[20]; TEL: String[7] end;
var
rec: TRec;
Описание записей возможно и без использования имени типа, на- пример:
var
rec: Record
FIO: String[20]; TEL: String[7] end;
Обращение к записи в целом допускается только в операторах присваивания, где слева и справа от знака присваивания используют- ся имена записей одинакового типа. Во всех остальных случаях опе- рируют отдельными полями записей. Чтобы обратиться к отдельной компоненте записи, необходимо задать имя записи и через точку ука- зать имя нужного поля, например: rec.FIO, rec.TEL – такое имя называется составным. Компонентой записи может быть также за- пись, в таком случае составное имя будет содержать не два, а боль- шее количество имен.
Обращение к компонентам записей можно упростить, если вос- пользоваться оператором присоединения with. Он позволяет заме-
72
нить составные имена, характеризующие каждое поле, просто на имена полей, а имя записи определить в операторе присоединения:
with rec do оператор;
rec – имя записи, оператор – оператор, простой или со- ставной.
Оператор представляет собой область действия оператора при- соединения, в пределах которой можно не использовать составные имена.
with rec do begin
FIO:='Иванов А.А.'; TEL:='2223322'; end;
Такая алгоритмическая конструкция полностью идентична сле- дующей:
rec.FIO:='Иванов А.А.'; rec.TEL:='2223322';
Инициализация записей может производиться с помощью типизи- рованных констант:
type
RecType = Record x,y: Word;
ch: Char;
dim: Array[1..3] of Byte end;
const
Rec: RecType = ( x: 127; y: 255;
ch: 'A';
dim: (2, 4, 8) );
Особой разновидностью записей являются записи с вариантами, которые объявляются с использованием зарезервированного слова case. С помощью записей с вариантами можно одновременно со- хранять различные структуры данных, которые имеют большую об- щую часть, одинаковую во всех структурах, и некоторые небольшие отличающиеся части.
Например, сконструируем запись, в которой мы будем хранить данные о некоторой геометрической фигуре (отрезок, треугольник, окружность).
type
TFigure = record
73
type_of_figure: string[10]; color_of_figure: byte;
...
case integer of
1:(x1,y1,x2,y2: integer);
2:(a1,a2,b1,b2,c1,c2: integer);
3:(x,y: integer; radius: word);
end;
var figure: TFigure;
Таким образом, в переменной figure будут храниться данные как об отрезке, так и о треугольнике или окружности. Надо лишь в зависимости от типа фигуры обращаться к соответствующим полям записи.
Замечание. Индивидуальные поля для каждого из типов фигур за- нимают тем не менее одно адресное пространство памяти, а это оз- начает, что одновременное их использование невозможно. В любой записи может быть только одна вариантная часть. После окончания вариантной части в записи не могут появляться никакие другие поля. Имена полей должны быть уникальными в пределах той записи, где они объявлены.
4.2.3. Множества
Понятие множества в языке Pascal основывается на математиче- ском представлении о конечных множествах: это ограниченная сово- купность различных элементов. Для построения конкретного множе- ственного типа используется перечисляемый или интервальный тип данных. Тип элементов, составляющих множество, называется базо- вым типом.
Множественный тип описывается с помощью служебных слов
Set of:
type M = Set of B; М – множественный тип, В – базо- вый тип.
Описание переменной множественного типа:
type
M = Set of 'A'..'D'; var
MS: M;
Принадлежность переменных к множественному типу может быть определена прямо в разделе описания переменных:
var C: Set of 0..7;
74
Константы множественного типа записываются в виде заключен- ной в квадратные скобки последовательности элементов или интер- валов базового типа, разделенных запятыми:
['A', 'C'] [0, 2, 7] [3, 7, 11..14]
Константа вида [ ] означает пустое подмножество. Количество ба- зовых элементов не должно превышать 256. Инициализация величин множественного типа может производиться с помощью типизиро- ванных констант:
const seLit: Set of 'A'..'D'= [];
Порядок перечисления элементов базового типа в константах без- различен.
Значение переменной множественного типа может быть задано конструкцией вида [T], где T – переменная базового типа.
Допустима конструкция: type T = set of char; Множество включает в себя набор элементов базового типа, все
подмножества данного множества, а также пустое подмножество. Так, переменная Т множественного типа var T: Set of 1..3; может принимать восемь различных значений:
[ ] [1] [2] [3] [1,2] [1,3] [2,3] [1,2,3]
К переменным и константам множественного типа применимы операции присваивания (:=), объединения (+), пересечения (*) и вы- читания (-):
['A','B'] + ['A','D'] даст ['A','B','D']; ['A','D'] * ['A','B','C'] даст ['A']; ['A','B','C'] - ['A','B'] даст ['C'].
Результат выполнения этих операций есть величина множествен- ного типа.
К множественным величинам применимы операции: тождествен- ность (=), нетождественность (<>), содержится в (<=), содержит (>=).
Результат выполнения этих операций имеет логический тип:
['A','B'] = ['A','C'] даст FALSE;
['A','B'] <> ['A','C'] даст TRUE; ['B'] <= ['B','C'] даст TRUE; ['C','D'] >= ['A'] даст FALSE.
Кроме этих операций для работы с величинами множественного типа в языке используется операция in, проверяющая принадлеж- ность элемента базового типа, стоящего слева от знака операции, множеству, стоящему справа от знака операции. Результат выполне- ния этой операции – логический. Операция проверки принадлежно-
75
сти элемента множеству часто используется вместо операций отно- шения, например:
'A' in ['A', 'B'] даст TRUE, 2 in [1, 3, 6] даст FALSE.
Пример программы
Описание: в программе реализован знаменитый метод Шерлока Холмса – метод исключений (Детективная история Шерлока Холмса).
В программе используются следующие английские слова:
actress – актриса; colonel – полковник; countess – графиня; baronet – баронет; drwatson – д-р Ватсон; maid – служанка; minister – ми-
нистр; mp – моя персона; moriarty – Мориарти; narrator – рассказ-
чик; sheepdog – овчарка; stranger – иностранец; suspects – подозре-
ваемые; murder – убийца; body – тело; roоm – комната.
Program detectiv; uses crt;
type persons=(actress,colonel, countess, baronet, drwatson, maid, minister, mp, moriarty, narrator, sheepdog, stranger); {имена участников событий}
setpersons=set of persons; {структура информационной модели участников событий}
const
sppersons: array [persons] of string=({actress-}('актриса'), {colonel-}('полковник'),{countess -}('графиня'),{baronet-} ('баронет'),{drwatson-} ('Ватсон'),
{maid -} ('служанка'),{minister -} ('министр'), {mp -} ('Холмс'),{moriarty -}('Мориарти'),
{narrator -} ('рассказчик'),{sheepdog -} ('овчарка'),{stranger -} ('иностранец')); var
suspects{подозреваемые}, tempted{заинтересованные в смер- ти},
able {возможные участники}, away {имеющие железное алиби}, good {люди высоких нравственных и моральных качеств} :
setpersons;
murderer,body:persons; {убийца и убитый} location: string; {место убийства} {процедура ввода значения перечисляемого типа – имени участ-
ника событий. Процедура вводит со стандартного устройства ввода строку символов с именем и формирует выходной параметр перечисляемого типа persons}
procedure readpersons(var name:persons); var s:string;
i:persons; begin
readln(s);
76
for i:=actress to stranger do if sppersons[i]=s then begin name:=i;
exit {выход из блока, т.е. из процедуры} end;
writeln('Ошибка ввода!!!');
HALT {прекращение выполнения программы} end;
{процедура вывода значения перечисляемого типа persons} procedure writepersons(name:persons);
begin write(sppersons[name])
end;
{процедура ввода значений в множество типа setpersons со стандартного устройства ввода, при вводе одно значение от другого отделяется пробелом}
procedure readset(var mn:setpersons); label 1;
var s{строка с введенными значениями}, r{cтрока с одним значением}:string; i,name:persons;{текущее и введенное значения}
j,beg,fin:integer;{для фиксации позиций в строке ввода} begin
mn:=[];
{чтение строки символов со значениями} readln(s);
if length(s)=0 then exit;{строка пустая – выход} {разбор строки по элементам}
beg:=1;
for j:=1 to length(s) do begin
if (s[j]=' ')or(j=length(s)) then begin
if s[j]=' ' then fin:=j else fin:=length(s)+1; if fin>beg+1 then begin r:=copy(s,beg,fin-beg);
for i:=actress to stranger do if sppersons[i]=r then begin name:=i;
goto 1 end;
writeln('Ошибка ввода!!!');
Halt;
1: mn:=mn+[name]; beg:=fin+1;
end
else beg:=fin+1 {подавление пробелов} end;
end;
end{readset};
{процедура вывода значений множества типа setpersons на стандартное устройство вывода}
77
procedure writeset(mn:setpersons);
var i:persons;{текущее значение для вывода} k:integer;{количество значений, выведенных в одну строку}
begin k:=0;
for i:=actress to stranger do if i in mn then begin write(sppersons[i]+' '); k:=k+1;
if k=6 then begin writeln;
k:=0; end end;
if k<>0 then writeln end;
{функция определения мощности множества типа setpersons} function card(mn:setpersons):integer;
var i:persons;{имя элемента множества} k:integer;{счетчик числа элементов множества} begin
k:=0;
for i:=actress to stranger do if i in mn then k:=k+1; card:=k;
end; begin
clrscr;
{процесс исключения } {нет ни одного человека вне подозрений}
suspects:=[actress..stranger]; writeln ; writeln;
writeln('Итак, Вы поставлены в тупик, не правда ли?'); writeln('Ну, Вы знаете методы, давайте используем их.'); writeln('Во-первых, скажите мне, кто убит'); writeln('Возможный ответ:');
writeset(suspects);
readpersons(body); if body=drwatson then
writeln('Подлое дело! Вы мне симпатичны.'); {самоубийство не предполагается} suspects:=suspects-[body];
write ('Теперь назовите мне всех,');
writeln(' кто был заинтересован в смерти - '); write('убит(а) '); writepersons(body); writeln('.'); writeln('Возможный ответ:');
writeset(suspects);
readset(tempted);
writeln('Где произошло преступление?'); readln(location);
78
writeln('Итак,'+location+'. Кто мог в это время здесь нахо- диться ?');
writeln('Возможный ответ:'); writeset(suspects); readset(able);
writeln('У кого железное алиби'); writeln('Возможный ответ:'); writeset(suspects); readset(away);
write ('КТО не мог совершить убийство'); writeln(' из нравственных принципов?'); writeln('Возможный ответ:'); writeset(suspects);
readset(good);
{вычисление подозреваемых} suspects:=suspects*tempted*able-away-good;
if suspects=[] then writeln('Я боюсь указать кандидата.') else if card(suspects)=1 then begin {вывод убийцы} murderer:=actress;
while not(murderer in suspects)and(murderer<stranger) do murderer:=succ(murderer);
write('Убийца - '); writepersons(murderer); writeln; end
else begin
for murderer:=actress to stranger do
if murderer in suspects then write(sppersons[murderer], ' ');
writeln end; end.
4.2.4. Файлы
Введение файлового типа в язык Pascal вызвано необходимостью обеспечить возможность работы с периферийными (внешними) уст- ройствами ПК, предназначенными для ввода, вывода и хранения данных.
Файловый тип данных или файл определяет упорядоченную сово- купность произвольного числа однотипных компонент. Понятие файла достаточно широко. Это может быть обычный файл на диске, коммуникационный порт ПК, устройство печати, клавиатура и т.д.
При работе с файлами выполняются операции ввода-вывода. Опе- рация ввода означает перезапись данных с внешнего устройства (из входного файла) в оперативную память ПК, операция вывода – это пересылка данных из оперативной памяти на внешнее устройство (в выходной файл).
79
Файлы на внешних устройствах часто называют физическими файлами. Их имена определяются операционной системой. В про- граммах на языке Pascal имена файлов задаются с помощью строк. Например, имя файла на диске может иметь вид:
'LAB1.DAT'
'c:\ABC150\pr.txt' 'my_files'
Типы файлов. Pascal поддерживает три типа файлов: текстовые файлы, типизированные файлы, нетипизированные файлы (файлы прямого доступа).
Доступ к файлу в программе происходит с помощью переменных файлового типа.
Описание: file of тип – типизированный файл; text – текстовый файл;
file – нетипизированный файл.
var
f1: file of char; {типизированный файл симво- лов}
f2: file of integer; {типизированный файл це- лых чисел}
f3: file; {нетипизированный файл} t: text; {текстовый файл}
Стандартные процедуры и функции при работе с файлами
Любые дисковые файлы становятся доступными программе после связывания их с файловой переменной, объявленной в программе. Все операции в программе производятся только с помощью связан- ной с ним файловой переменной.
Assign(f, FileName) – связывает файловую переменную f с физическим файлом, полное имя которого задано в строке FileName. Установленная связь будет действовать до конца рабо- ты программы или до тех пор, пока не будет сделано переназначение. После связи файловой переменной с дисковым именем файла в про- грамме нужно указать направление передачи данных (открыть файл). В зависимости от этого направления говорят о чтении из файла или записи в файл.
Reset(f) – открывает для чтения файл, с которым связана файловая переменная f. После успешного выполнения процедуры Reset файл готов к чтению из него первого элемента. Процедура
80
