Книга: Песни о Паскале
Глава 36 Множества в Паскале
Разделы на этой странице:
Глава 36
Множества в Паскале
Зная силу математических множеств, Никлаус Вирт – «отец» языка Паскаль – ввел в язык тип данных множество и предусмотрел операции с ним.
Элементами множеств здесь могут быть числа, символы и булевы данные – то есть порядковые типы данных размером в один байт. Стало быть, мощность множеств в Паскале не превышает 256.
Объявление множеств
Множества объявляются конструкцией вида
SET OF <диапазон или тип>
Вот примеры объявления переменных типа множество.
{ объявление множества } { возможные элементы множества }
var SN1 : set of 10..100; { числа от 10 до 100 }
SN2 : set of byte; { числа от 0 до 255 }
SC1 : set of ’a’..’z’; { только малые латинские буквы }
SC2 : set of Char; { все символы }
Поскольку мощность множеств в Паскале не превышает 256, множества SET OF BYTE и SET OF CHAR представляют множества предельной мощности.
Присвоение значений множествам
Переменным типа множество присваивают значения выражений того же типа, вот примеры таких операторов.
SN1:= [10, 20, 50]; { содержит три элемента }
SN2:= [11..20, 51..60]; { содержит 20 элементов }
SN2:= [0..255]; { содержит 256 элементов от 0 до 255 }
SN2:= SN1; { копия другого множества }
SC1:= [’z’, ’y’, ’x’]; { содержит три элемента }
SC2:= [’0’..’9’]; { содержит 10 элементов }
Как видите, для записи множеств в Паскале используют квадратные скобки, а не фигурные. Что позволено в записи множеств, и что запрещено?
Подряд идущие элементы можно заменять диапазоном с указанием крайних значений. Допустимо перечислять элементы в произвольном порядке и даже вставлять дубликаты, – они все равно будут отброшены. Вот примеры трех совершенно одинаковых по результату операторов.
SN1:= [5..8]; { множество задано диапазоном }
SN1:= [8, 7, 6, 5]; { то же множество, но в другом порядке }
SN1:= [5..8, 6, 6]; { трижды указано число 6, дубликаты будут отброшены }
Множеству любого типа можно присвоить пустое значение, например:
SB1:= []; SN1:= []; SC1:= [];
Пустое множество изображается парой квадратных скобок, между которыми ничего нет. Нельзя считать пустым множество [0], поскольку оно содержит один элемент – число ноль.
Элементами множеств могут быть только значения переменных и выражений соответствующего типа.
var k, n : byte; c: char;
...
k:= 10; n:= 20;
SN1:= [1..k, n+5]; { 1..10, 25 }
c:= ’m’;
SC1:= [c, ’a’, ’b’]; { ’m’, ’a’, ’b’ }
Компилятор не позволит включать в множество элементы, не относящиеся к нему, а также смешивать элементы разных типов, вот примеры таких ошибок.
SN1:= [5..200]; { в объявлении SN1 указан диапазон от 10 до 100 }
SC1:= [’a’, ’b’, 5]; { вместо символа ’5’ указано число 5 }
Операции с множествами
В Паскале предусмотрены три известные вам вычислительные операции с множествами, а также сравнение множеств и проверка на вхождение элемента в множество.
Вычислительные операции – объединение, пересечение и вычитание – записывают на Паскале так:
SN2:= [3, 7] + [5, 2]; { объединение = [2, 3, 5, 7] }
SN2:= [2..10] * [8..20]; { пересечение = [8, 9, 10] }
SN2:= [2..10] – [8..20]; { разность = [2..7] }
Множества, объединенные знаками операций и круглыми скобками, образуют выражение, например:
SN2:= (SN1 + [0..15]) * SN2;
Выражения, составленные из множеств, очень похожи на выражения из чисел, но вычисляются по другим правилам. Это обманчивое сходство может спровоцировать ошибку – смешение в одном выражении чисел и множеств. Предположим, вы хотите добавить к множеству число, содержащееся в переменной K. Следующее выражение будет неверным.
SN1:= SN1 + K; { сложение множества с числом – ошибка }
Правильно будет так:
SN1:= SN1 + [ K ]; { добавляется множество из одного элемента }
Разумеется, за ошибками такого рода присматривает компилятор, проверьте его реакцию на практике.
Сравнение множеств
Множества можно сравнивать между собой, получая в результате булево значение – TRUE или FALSE.
Два множества равны, если содержат одни и те же элементы.
if SN1 = SN2 then … else …
Множества неравны, если одно из них содержит, хотя бы один элемент, которого нет в другом.
if SN1 <> [15, 17, 19] then … else …
Проверка на подмножество (<=) отвечает на вопрос: все ли элементы первого множества входят во второе?
if SN1 <= SN2 then … else …
Проверкой на надмножество (>=) выясняют, все ли элементы второго множества входят в первое.
if SN1 >= SN2 then … else …
Проверка на вхождение элемента в множество (операция IN)
Входит ли некоторый элемент в множество? Это можно выяснить так:
var N : byte; S : set of byte;
...
if ([N] * S) <> [] then { N входит в S } else { не входит }
Понятно, что, если число N входит в множество S, то пересечение [N]*S не будет пустым. Но проще выяснить это операцией IN – она введена специально для этого. Операция дает TRUE, если значение перечислимого типа входит в данное множество, например:
if N in S then { N входит в S } else { не входит }
if 20 in S then { 20 входит в S } else { не входит }
Решение директорской задачи
Вернемся к временно покинутому директору Семену Семеновичу. Напомню стоящую перед нами задачу: есть текстовый файл, каждая строка которого содержит список номеров учеников, состоящих в некотором кружке.
2 11 4 13
9 17 12 11 3 5 18
14 2 13 15 20
Надо составить список нигде не числящихся разгильдяев.
Можно ли воспринимать эти списки как множества? Вероятно, да, судите сами:
• каждый список содержит номер ученика не более одного раза (ошибочные повторные записи все равно отбросят);
• порядок следования в списке не важен;
• список может быть пустым (если никто не записался в этот кружок).
Хорошо, а будет ли множеством список всех учеников школы? Конечно. Такое множество будет полным, поскольку содержит все возможные элементы. А раз так, директорскую задачку решим через множества.
Множество тех, кто записался хотя бы в один кружок, найдем объединением отдельных множеств-кружков (S1 + S2 + S3). Вычтя это объединение из полного множества учеников, получим множество уклонившихся. Вот и все решение! На Паскале это запишется так:
var R, S1, S2, S3 : set of 1..250;
begin
S1:= [ 2, 11, 4, 13 ]; { 1-й кружок }
S2:= [ 9, 17, 12, 11, 3, 5, 18 ]; { 2-й кружок }
S3:= [ 14, 2, 13, 15, 20 ]; { 3-й кружок }
R:= [1..250] – (S1 + S2 + S3); { R – множество уклонившихся }
end.
Выделеное выражение в скобках – это множество учеников, состоящих хотя бы в одном кружке. Итак, решение задачи вместилось в одну строчку! Нет, не зря мы терпели математика и корпели над множествами!
Показанное выше решение – это работающая программа, которую можно запустить в пошаговом режиме, и через отладчик увидеть результат. Сделайте это. А как быть с вводом и выводом множеств? Ведь исходные данные хранятся в файле, а результат – переменную R – тоже надо вывести в файл или на экран. Вот этим мы и займемся в следующей главе.
Итоги
• Множества – это инструмент, взятый в Паскаль из математики.
• В Паскале применяют конечные множества, элементами которых могут быть числа, символы и булевы значения. Мощность множеств в Паскале не превышает 256.
• В Паскале предусмотрен ряд операций с множествами: объединение, пересечение, вычитание, сравнение, а также проверка на вхождение элемента в множество.
• Сравнение двух множеств дает булев результат, который используют в условных и циклических операторах.
• Операция IN – удобное средство для проверки вхождения одного элемента в множество, она тоже дает булев результат.
А слабо?
А) Найдите ошибки в следующих операторах.
type TNumbers = set of 1..300;
TChars = set of char;
TBytes = set of byte;
var c1, c2 : TChars;
b1, b2 : TBytes;
begin
c1:= [1..9];
c2:= ['1'..'9'];
c2:= c2 + ’0’;
c2:= c2 + [0];
b1:= c1;
b2:= b1 + [1,7,3];
Writeln(b1=b2);
Writeln(1 in b2);
Writeln([1] in b2);
Writeln(b1 in b2);
end.
Б) Напечатайте 20 случайных чисел в диапазоне от 1 до 50 так, чтобы каждое число встретилось в распечатке лишь по разу. Подсказка: после генерации числа функцией Random проверьте его на вхождение в множество уже напечатанных чисел.
В) Введите программу решения директорской задачи (см. предыдущую страницу), а затем запустите её в пошаговом режиме (клавишей F7). Перед запуском вставьте все переменные в окно обзора переменных «Watch» и проследите за их изменением. Напомню, что о средствах отладки рассказано в главе 21.
- Только для взрослых
- Детям до 16–ти
- Глава 1 Путь далек у нас с тобою…
- Глава 2 Вместо теории
- Глава 3 Консольный интерфейс
- Глава 4 Оружие – к бою!
- Глава 5 Программа номер один
- Глава 6 Подготовка к следующему штурму
- Глава 7 Развиваем успех
- Глава 8 Постоянные и переменные
- Глава 9 Переменные: продолжение знакомства
- Глава 10 Условный оператор
- Глава 11 Операторный блок
- Глава 12 Цикл с проверкой в конце
- Глава 13 Правда и кривда
- Глава 14 Дважды два – четыре
- Глава 15 Айда в Монте-Карло!
- Глава 16 Делу время, а потехе час
- Глава 17 И вновь за парту
- Глава 18 Аз, Буки
- Глава 19 Процедуры и функции: разделяй и властвуй
- Глава 20 Процедуры: первый опыт
- Глава 21 Отладка
- Глава 22 О передаче параметров
- Глава 23 Функции
- Глава 24 Криптография
- Глава 25 Текстовые файлы
- Глава 26 Я не читатель, – я писатель!
- Глава 27 Дайте кораблю минутный отдых!
- Глава 28 Редактор и справочная система
- Глава 29 Читайте по-новому
- Глава 30 Журнальная история
- Глава 31 Финал журнальной истории
- Глава 32 Порядковые типы данных
- Глава 33 Вещественные числа
- Глава 34 Структура программы
- Глава 35 Множества
- Глава 36 Множества в Паскале
- Глава 37 Ввод и вывод множеств
- Глава 38 Множества в «бою»
- Глава 39 Командная игра (массивы)
- Глава 40 Пристрелка на знакомых мишенях
- Глава 41 По порядку, становись!
- Глава 42 Кто ищет, тот всегда найдет
- Глава 43 Сортировка по-взрослому
- Глава 44 Строки
- Глава 45 Очереди и стеки
- Глава 46 Огромные числа
- Глава 47 Системы счисления
- Глава 48 Железная логика
- Глава 49 Сложные массивы
- Глава 50 Неспортивные рекорды (записи)
- Глава 51 Указатели в море памяти
- Глава 52 Динамические переменные
- Глава 53 Массив указателей
- Глава 54 Односвязные списки
- Глава 55 Слова, слова, слова…
- Глава 56 И снова очереди, и снова стеки…
- Глава 57 Графомания
- Глава 58 По графу шагом марш!
- Глава 59 Крупные проекты
- Глава 60 Мелкие хитрости
- Глава 61 «Кубики» программиста (ООП)
- Глава 62 Самое интересное только начинается!
- Приложение А Установка и настройка IDE Borland Pascal
- Приложение Б Консольная программа в среде Delphi
- Приложение В Особенности IDE Pascal ABCNet
- Приложение Г Зарезервированные слова
- Приложение Д Ошибки компиляции
- Приложение Е Ошибки исполнения
- Приложение Ж Директивы управления компиляцией
- Приложение З Назначение пунктов меню
- Приложение И Стандартная кодировка символов MS–DOS
- Приложение К Некоторые встроенные процедуры и функции
- Приложение Л Перечень программ
- Приложение М Пример олимпиадной задачи
- Библиография
- Содержание книги
- Популярные страницы
- Песни о Паскале
- Детям до 16–ти
- Только для взрослых
- Глава 1 Путь далек у нас с тобою…
- Глава 10 Условный оператор
- Приложение З Назначение пунктов меню
- Глава 16 Делу время, а потехе час
- Глава 15 Айда в Монте-Карло!
- Приложение В Особенности IDE Pascal ABCNet
- Глава 11 Операторный блок
- Приложение К Некоторые встроенные процедуры и функции
- Глава 55 Слова, слова, слова…