const CSize = 1000;
type TBoolSet = array [1..CSize] of Boolean;
var BS : TBoolSet;
Теперь условимся, что массив, заполненный значением FALSE, – это пустое множество. А если множество содержит числа A и B, то соответствующие им элементы массива BS[A] и BS[B] содержат TRUE. Тогда операции с этим придуманным нами типом-множеством можно выполнять так (справа показаны аналогичные операции с обычным множеством чисел S).
FillChar(BS, SizeOf(BS), false); { S:= [] – пустое множество }
FillChar(BS, SizeOf(BS), true); { S:= [1..1000] – полное множество }
BS[N]:= true; { S:= S + [N] – добавление элемента }
BS[N]:= false; { S:= S – [N] – удаление элемента }
if BS[N] then … { if N in S then … – проверка вхождения }
Воспользуйтесь таким массивом для поиска простых чисел в диапазоне от 1 до 1000.
Г) Садовая ограда. Вернувшись с курорта, фермер Лефт обнаружил на своем поле чудом выросший сад. Для сохранения деревьев он обнес его прямоугольной оградой. Пусть ширина и высота поля заданы константами CX и CY, пустые места обозначены точками, а деревья – звездочками. Засадите поле случайным образом и распечатайте его. Затем найдите левый верхний и правый нижний углы для ограды и постройте её символом решетки. Ограда должна охватывать деревья, но не выходить за пределы поля (то, что выходит за пределы, не строить). Распечатайте сад с оградой.
Глава 50
Неспортивные рекорды (записи)
Кушать подано!
Вообразите себя в гостях за столом, накрытым посудой и вкусностями. Только стол этот накрыт необычно: в одном углу – стопка тарелок, в другом – букет вилок, а там собраны все ножи. Неудобно, однако! Голодных гостей такие мелочи, ясно, не остановят, но согласитесь, – так накрывать не принято.
Или взять ранец со школярским добром: книгами, тетрадями, ручками и карандашами. Что, если нагрузить одного ученика всеми учебниками класса, другого – всеми тетрадями, а третьего – карандашами? Удобно им будет?
Однако ж, мы поступили именно так в одной из программ главы 41. Вспомните сортировку таблицы футбольного чемпионата. Там мы завели два массива: один – для набранных очков, другой – для названий команд. А затем в ходе сортировки меняли местами элементы этих массивов (программа «P_41_3»). Добавляя в таблицу чемпионата другие сведения о командах (забитые и пропущенные мячи, выигрыши, проигрыши и так далее), нам придётся заводить для них свои массивы. А потом возиться с перестановкой их элементов при сортировке, – тоска!
Нередко мы сталкиваемся с набором разнородных, но логически связанных предметов или данных, как в упомянутых выше случаях. И воспринимаем такие наборы как нечто целое, – это освобождает наш мозг от второстепенных деталей. Вот бы и в программировании найти средство логического соединения разнородных элементов!
Записи
В современных языках такое средство есть. В Паскале оно называется записью, по-английски – RECORD. «Рекорд» – знакомое словцо, не так ли? – оно имеет отношение к спорту. В самом деле, то, что мы называем спортивными рекордами, изначально было лишь записью в журнале регистрации спортивных достижений: кем, когда, где и сколько. Отсюда и пошло слово «рекорд».
Но вернемся к Паскалю. Итак, запись объединяет в единый набор логически связанные, но разнородные данные и дает этому набору имя. Такое объединение обозначают парой ключевых слов RECORD-END и размещают либо в секции объявления типов, либо в секции объявления переменных. Возьмем футбольную команду и соединим её название и набранные ею очки. Объявим для команды тип данных, который так и назовем – Team – «команда». А затем учредим две переменные этого типа, вот как это выглядит.
type Team = record { тип данных «команда» }
Aces : integer; { набранные очки }
Name : string; { название команды }
end;
var Team1, Team2 : Team; { две переменных типа «команда» }
Может показаться, что между ключевыми словами RECORD и END объявлены переменные Aces и Name. Так ли это? И да, и нет. Нет, – потому, что в секции TYPE переменные не объявляют. Да, – потому, что внутри переменных Team1 и Team2 (объявленных чуть ниже в секции VAR) действительно «живут» переменные с именами Aces и Name. Только называются они теперь полями переменных Team1 и Team2.
Как получить доступ к этим полям, спрятанным внутри переменных? Надо к имени переменной добавить так называемый квалификатор поля, или проще – имя этого поля. Вот так присваивают значения полям переменной Team1.
Team1.Aces := 25;
Team2.Name := ’Dinamo’;
Как видите, квалификатор поля отделяют от имени переменной точкой. Поля – это «кусочки» более сложных переменных (в данном случае переменных Team1 и Team2). Во всем остальном, кроме способа доступа, поля записей ничем не отличаются от обычных переменных.
Переменные, построенные на основе записей, называют структурными переменными или агрегатами. В чем их прелесть? В том, что обращаться с ними можно как с единым целым, например, копировать.
Team2 := Team1; { перенос всех полей из Team1 в Team2 }
Это существенно упрощает программы, в чем вы скоро убедитесь. А в сочетании с особыми типами данных – указателями – записи превращаются в «волшебные кирпичи», пригодные для возведения сложнейших структур, отражающих реальности нашего мира.
Второй тайм
Слышен свисток к началу второго тайма, вернемся на футбольное поле, точнее к программе «P_41_3», сортирующей команды в порядке занятых ими мест. Сотворим новую версию этой программы «P_50_1», заменив два массива (набранных очков и названий команд) одним. План игры на второй тайм таков. Объявим два типа данных: запись и массив записей. Первый из них – запись – будет содержать сведения об отдельной команде.
type TTeam = record
mAces : integer; { набранные очки }
mName : string; { названия команд }
end;
Напомню, что для улучшения читаемости программ мы условились начинать названия типов данных с буквы «T». По этой причине тип данных «команда» (Team) стал называться TTeam. Подобное соглашение примем и для полей записей. Чтобы отличить их от прочих переменных, будем начинать имена полей с буквы «m» (от Member – «элемент», «участник»). Поэтому поля названы здесь как mAces и mName.
Второй из объявляемых типов данных – TChamp (Champ – «чемпионат») – представляет собой массив футбольных команд.
TChamp = array [1..CSize] of TTeam; { тип для массива команд }
Стало быть, каждый элемент этого типа содержит внутри себя два поля: число mAces и строку mName. Теперь можно объявить и переменную типа TChamp, то есть, массив команд.
var Champ : TChamp; { массив команд }
Доступ к элементам массива Champ осуществляется так:
Champ[i] – i–й элемент массива, то есть i–я команда (тип TTeam)
Champ[i].mAces – количество набранных очков i–й командой