Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Алгоритмизация и языки программирования. Учебно-методический комплекс.pdf
X
- •1. СИЛЛАБУС ДИСЦИПЛИНЫ ДЛЯ СТУДЕНТОВ
- •Тема 1. Понятие алгоритма, свойства, типы, исполнители
- •Структура программы.
- •Имена, ключевые слова и знаки операций
- •Тема 7. Символьные типы данных.
- •Обработка символьных данных.
- •Тема 9. Строки. Строковые процедуры.
- •Функции
- •Тема 11. Множества (Set)
- •Работа с текстовыми файлами
- •Тема 13. Записи
- •Тема 14. Построение изображений на экране
- •Отображение точки на экране
- •Отображение линий на экране
- •Построение прямоугольников на экране
- •Построение многоугольников
- •Построение дуг, эллипсов и окружностей
- •Основная литература
- •Дополнительная литература
- •ГЛОССАРИЙ

Представление множеств линейными массивами
Задав линейный массив достаточной длины, можно "вручную"
сымитировать множество для более широкого, чем 256 элементов,
диапазона значений. Например, чтобы работать с множеством,
содержащим 10 000 элементов, достаточно такого массива:
set_arr: array[1..10000] of boolean;
При таком способе представления возможно задать множество
до 65 000 элементов.
Для простоты изложения мы ограничимся только числовыми
множествами, однако все сказанное ниже можно применять и к мно-
жествам, элементы которых имеют другую природу. Итак, признаком
того, что элемент k является элементом нашего множества, будет
значение true в k-й ячейке этого массива.
Посмотрим теперь, какими способами мы вынуждены будем
имитировать операции над "массивными" множествами.
1. Проверка множества на пустоту может быть осуществлена
довольно просто:
pusto:= true;
for i:= 1 to N do
if set_arr[i] then begin pusto:= false;
break
end;
2. Проверка элемента на принадлежность множеству также
не вызовет никаких затруднений, поскольку соответствующая
компонента массива содержит ответ на этот вопрос:
is_in:= set_arr[element];
3. Добавление элемента в множество нужно записывать так:
set_arr[element]:= true;
4. Удаление элемента из множества записывается анало-
гичным образом:
set_arr[element]:= false;
5. Построение пересечения множеств реализуется как про-
верка вхождения каждого элемента в оба множества и последующее
61

добавление удовлетворивших этому условию элементов в результи-
в каждом), это число можно увеличить в 8 раз, перейдя от байтов к
рующее множество.
6. Построение объединения множеств аналогичным образом
базируется на проверке вхождения элемента хотя бы в одно из
объединяемых множеств и дальнейшем добавлении элементов в
результирующее множество.
7. Построение разности двух множеств также опирается на
проверку вхождения элемента в оба множества, причем добавление
элемента в создаваемое множество происходит только в том случае,
если элемент присутствует в множестве-уменьшаемом и одновременно отсутствует в множестве-вычитаемом.
8. Проверка двух множеств на равенство не требует особых
пояснений:
equal:= true;
for i:=1 1 to N do
if set1[i]<> set2[i]
then begin
equal:= false;
break
end;
9. Проверка двух множеств на включение (set1<set2) тоже не
потребует больших усилий:
subset:= true;
for i:= 1 to N do
if set1[i]and not set2[i]
then begin
subset:= false;
break
end;
Представление множеств битовыми массивами
В случае, если 65 000 элементов недостаточно для задания всех
необходимых множеств (например, 10 множеств по 10 000 элементов
битам. Тогда 1 байт будет хранить информацию не об одном, а сразу
о восьми элементах: единичный бит будет означать наличие элемента
в множестве, а нулевой бит - отсутствие.
62

Задавая битовый массив, начнем нумерацию его компонент с 0:
> div 8 будет
set_bit: array[0..N-1] of byte;
Тогда результатом операции <номер_элемента
номер той компоненты массива, в которой содержится информация об этом элементе. А вот номер бита, в котором содержится
информация об этом элементе, придется вычислять более сложным
образом:
bit:= <номер_элемента> mod 8;
if bit=0 then bit:= 8;
Эти вычисления потребуются нам еще не раз, поэтому запишем
их снова, более строго, а затем будем использовать по умолчанию
(element - это "номер" обрабатываемого элемента в нашем множестве):
kmp:= element div 8; {номер компоненты массива}
bit:= element mod 8; {номер бита}
if bit=0 then bit:= 8;
Перечислим теперь действия, которые потребуются для реали-
зации операций над множествами, заданными битовыми массивами.
1. Проверка множества на пустоту почти не будет отличаться
от аналогичной проверки в случае представления множества не
битовым, а обычным массивом.
2. Проверка элемента на принадлежность множеству потре-
бует несколько большей изворотливости ведь нам теперь нужно
вычленить соответствующий бит:
if set_arr[kmp]and(1 shl(bit-1))=0
then is_in:= false
else is_in:= true;
Поясним, что здесь используется операция "побитовое и",
которая работает непосредственно с битами нужной нам компоненты
массива и числа, состоящего из семи нулей и единицы на месте с
номером bit.
3. Добавление элемента в множество теперь будет записано так:
set_arr[kmp]:= set_arr[kmp]or(1 shl(bit-1));
Здесь нельзя использовать обычную операцию сложения (+), так
как если добавляемый компонент уже содержится в множестве (то
есть соответствующий бит уже имеет значение 1), то в результате
63

сложения 1+1 получится 10: единица автоматически перенесется в
старший бит, а на нужном месте окажется 0.
4. Удаление элемента из множества придется записать более
сложным образом:
set_arr[kmp]:= set_arr[kmp] and not (1 shl(bit-1));
Операция not превратит все 0 в 1 и наоборот, следовательно,
теперь в качестве второго операнда для побитового and будет
фигурировать число, состоящее из семи единиц и нуля на месте с
номером bit. Единицы сохранят любые значения тех битов, которые
должны остаться без изменения, и лишь 0 "уничтожит" значение
единственного нужного бита.
5. Пересечение множеств реализуется теперь при помощи
операции "побитовое и":
for i:= 0 to N-1 do set_res[i]:= set1[i] and set2[i];
6. Объединение множеств реализуется при помощи операции
"побитовое или":
for i:= 0 to N-1 do
set_res[i]:= set1[i] or set2[i];
7. Разность двух множеств может быть построена так:
for i:= 0 to N-1 do
set_res[i]:= (set1[i] or set2[i]) and not set2[i];
Поясним, что здесь мы вначале прибавляем содержимое второго
множества к первому, чтобы затем быть полностью уверенными в
правомерности операции вычитания.
8. Проверка двух множеств на равенство по-прежнему не
требует особых пояснений:
equal:= true;
for i:=0 to N-1 do
if set1[i]<> set2[i] then
begin
equal:= false;
break
9. Проверка двух множеств на включение (set1<set2) будет
производиться по схеме: "Если (A\B) B=A, то B A", доказательство
которой настолько очевидно, что мы не станем на нем задерживаться:
subset:= true;
64
end;

for i:= 0 to N-1 do
if((set1[i] or set2[i])and not set2[i])
or set2[i] <> set1[i]
then begin subset:= false;
break
Замечание. Если предстоит многократно выполнять действия с
элементами битовых массивов, то используемые для этого значения
"единиц" удобнее всего сразу задать в специальном массиве:
{ed: array[1..8] of byte;}
ed[1]:=1;
for k:= 2 to 8 do ed[k]:= ed[k-1] shl 1;
И далее вместо громоздкой конструкции shl(bit-1) можно использовать просто ed[bit].
Тема 12. Файлы. Файловые переменные.
end;
Словом «файл» в программировании называется сразу несколько несовпадающих понятий. Во-первых, это файл операционной
системы – «поименованная часть диска». Во-вторых, это абстрактная
структура данных с последовательным доступом и, в третьих, пере-
менные файловых типов, реализующие эту структуру данных в
конкретном языке программирования.
Итак, файл - это самостоятельная последовательность символов,
записанная в постоянную память компьютера.
В английском языке слово "file" имеет вполне понятный смысл:
"вереница", что очень хорошо отражает внутреннюю структуру
любого файла. Файл - это именно вереница символов, причем свя-
занных в определенной последовательности: символы файла не могут
по своему желанию перепрыгивать с одного места на другое.
"Самостоятельность" файлов заключается в том, что они не
зависят от работы какой-либо программы. И даже если выключить
компьютер, файлы будут продолжать свое существование на винчестере или на дискете.
Файлы могут хранить в себе все, что поддается кодированию:
• исходные тексты программ или входные данные (тесты);
• машинные коды выполняемых программ (игры, вирусы,
обучающие и сервисные программы, др.);
• информацию о текущем состоянии какого-либо процесса;
65

• различные документы, в том числе и Интернет-страницы;
• картинки (рисунки, фотографии, видео);
• музыку;
По сфере использования в программировании:
• Файлы полезны, если объем входных данных превосходит
посильный при ручном вводе. (Крайним является случай, когда
входные или выходные данные заведомо не могут поместиться в
оперативной памяти.)
• Файлы нужны, если приходится многократно вводить одну и
ту же информацию, с минимальными изменениями или вовсе без
изменений (например, при отладке программы).
• Файлы необходимы, если нужно сохранять информацию о
результатах работы программы, полученных при вводе различных
входных данных (то есть: при поиске ошибок в программе).
• Например, если вашей программе необходимо получить два
или три числа (пять - уже многовато) или строку длиной символов
десять, вы вполне можете задавать такие данные с клавиатуры
вручную. Если же вам (а еще вероятнее - не вам, а некоему
усредненному и потому посредственному оператору) придется
вводить, скажем, массив чисел 10х10, то вероятность ошибки при
ручном вводе возрастает многократно. Значит, возможность этой
ошибки нужно исключить: записать данные в файл, который легко
отредактировать в случае необходимости. Кроме того, однажды
созданный файл можно использовать многократно (может быть, с
незначительными изменениями).
Разновидности файлов
В языке Pascal имеется возможность работы с тремя видами
файлов:
• текстовыми;
• типизированными;
• нетипизированными.
Последние два типа объединяются под названием бинарные:
информация в них записывается по байтам и потому не доступна для
просмотра или редактирования в удобных для человека текстовых
редакторах, зато такие файлы более компактны, чем текстовые.
В отличие от бинарных, текстовые файлы возможно создавать,
просматривать и редактировать "вручную" - в любом доступном
66

текстовом редакторе. Кроме того, при считывании данных из тексто-
ASSIGN (F,
Связь файловой переменной F с внешним файлом NAME. NAME -
или совместимого
типа. Имя типа должно быть написано в соответствии с правилами
, может включать путь и не должно превышать 79
CHDIR (PATH)
Изменение текущей директории. Устанавливает новый текущий
ства)
находится в параметре PATH
CLOSE (F)
Закрытие открытого файла
вого файла нет необходимости заботиться об их преобразовании: в
языке Pascal имеются средства автоматического перевода содержимого текстовых файлов в нужный тип и формат, и это позволяет
сэкономить немало времени и сил.
Работа с текстовыми файлами
Одним из типов данных в PASCAL является файловый тип,
представляющий собой последовательность однотипных компо-
нентов, расположенных на внешнем носителе. Тип этих компонентов
может быть любой, за исключением типа-файла.
В PASCAL файловые переменные используются для вводавывода информации.
Перед тем как осуществлять ввод-вывод, файловая переменная
должна быть связана с конкретным внешним файлом с помощью
процедуры ASSIGN. Этим файлом может быть файл на магнитном
диске или ленте, а также устройство вычислительного комплекса
(клавиатура, экран дисплея, принтер и т. д.). Затем файл должен быть
открыт для чтения и/или записи. После этого можно осуществлять
организацию ввода-вывода.
В PASCAL 7.0 имеется 3 категории файлов, работа с которыми
отличается друг от друга:
- текстовые (тип TEXT);
- типизированные (FILE OF <тип>);
файлы без типа (FILE).
В табл. 1 приведены стандартные процедуры и функции для
всех файлов.
Процедуры и
функции для
всех файлов
NAME)
переменная или константа типа STRING, CHAR
Назначение
MS DOS
символов. Если строка имени пустая, осуществляется связь со
стандартным файлом ввода или вывода (как правило, консолью)
каталог, путь к которому (включая, быть может, имя устрой
67

ERASE (F)
Уничтожение внешнего файла
GETDIR(N, S)
Получение текущего каталога накопителя. В переменную S
записывается текущий каталог накопители, номер которого указан
параметром N. Параметр N имеет следующие значения: О -
MKDIR(PATH)
Создание каталога
RENAME(F,
Переименование внешнего файла
RESET (F[,
Открытие существующего файла. Открывается существующий
REWRITE(F[,
Открывается новый пустой файл, и ему присваивается имя,
существует, то он уничтожается
RMDIR(PATH)
Удаление пустого каталога
EOF(F)
Конец файла
IORESULT
Результат последней операции ввода-вывода. Возвращает число 0,
вывода завершилась успешно, и другое число
текущий накопитель, 1 - накопитель А:, 2 - накопитель В: и т. д.
SIZE])
SIZE])
файл, с которым связана файловая переменная F, и указатель текущего компонента файла настраивается на начало файла.
Необязательный параметр целого типа SIZE используется только с
файлами без типа и задает размер пересылаемого элемента информации в байтах (по умолчанию 128)
заданное процедурой ASSIGN. Если файл с таким именем уже
если операция ввода-
-в противном случае. После применения этой функции параметр
состояния последней операции ввода-вывода сбрасывается в нуль
Текстовые файлы представляют собой совокупность символов,
разделенных на строки, причем в конце каждой строки стоит признак
конца строки.
Особенностью работы с текстовыми файлами является то, что
параметры, значения которых вводятся и выводятся с помощью
процедур READ или WRITE, могут быть не только типа CHAR или
STRING, но и других простых типов:
- целых, вещественных типов при вводе;
- целых, вещественных, логических типов при выводе.
Эти процедуры могут также работать и с ASCII-строками.
Имеется две стандартные файловые переменные для текстовых
файлов, которые автоматически открываются при запуске программы
и автоматически закрываются после работы:
INPUT - по умолчанию связанная с клавиатурой;
OUTPUT - по умолчанию связанная с экраном дисплея.
Если при работе с файлами типа TEXT в процедуре или функ-
ции не указана файловая переменная, считается, что используется
файловая переменная INPUT или OUTPUT. Текстовый файл может
68

быть открыт либо для чтения процедурой RESET, либо для записи
Процедуры и функции
для текстовых файлов
APPEND (F)
Открытие файла для добавления в конец информации
FLUSH (F)
Освобождение буфера выходного файла. Информация
READ (F, <список>)
Чтение из файла
READLN(F, <список>)
Чтение строки из файла
SETTEXTBUF(F, BUF [,
Назначение буфера ввода-вывода. Для файла, с кото-
WRITE(F, <список>)
Запись в файл
WRITELN(F, <список>)
Запись строки в файл
EOLN(F)
Конец строки файла
SEEKEOF(F)
Конец файла
SEEKEOLN(F)
Конец строки файла, пропускает в конце строки
процедурой REWRITE или APPEND.
Описание процедур и функций для работы с текстовыми файлами приведено в табл. 2.
Назначение
из буфера вывода записывается в файл, с которым
связана файловая переменная F
SIZE])
рым связана файловая переменная F, назначается буфер
ввода-вывода в виде переменной BUF любого типа
символы пробела и табуляции
Выводить в текстовый файл можно переменные любых базовых
типов (вместо значений логического типа выведется их строковый
аналог TRUE или FALSE) или строки. Структурированные типы
данных можно записывать только поэлементно.
Тема 13. Записи
Продолжая изучение структурированных типов данных, переходим к записям.
Как и массивы, записи являются структурами прямого доступа,
однако, в отличие от массивов, могут хранить элементы, относящиеся
к разным типам данных.
Таким образом, запись - это вектор, компоненты которого (поля)
могут относиться к разным типам данных.
Описание записей
В разделе var переменную типа запись описывают так:
var <имя_записи>: record <имя_поля1>: <тип_поля1>;
69

[<имя_поля2>: <тип_поля2>;]
[...]
end;
Имена полей должны подчиняться общим правилам построения
идентификаторов. Повторение имен полей внутри одной записи не
допускается.
Замечание: Имена полей могут совпадать с именами других
переменных, поскольку на самом деле являются составными:
<имя_записи>.<имя_поля>
Поэтому можно записать:
var x: real;
r: record x: real;
y: real
end;
Поля могут относиться к любым стандартным (базовым или
сконструированным) или определенным ранее типам, даже к файловому или процедурному.
Если несколько подряд идущих полей принадлежат к одному
типу данных, их описания можно объединить:
var
<имя_записи>: record<имя_поля1>,_,<имя_поляN>:<тип_полей>;
<имя_поляS>: <тип_поляS>;
...
end;
Например:
var zap1: record x,y: real;
i,j,k: integer;
flag: boolean;
s: set of 'a'..'z';
a: array[1..100] of byte;
data: record day:1..31;
month: 1..12;
year: 1900..2100;
end;
end;
Эта запись содержит 9 полей, три из которых сами являются
составными. Наиболее распространенный способ использования
70
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
