Rationale for Ada 2005: 6a Containers
RUSTOPBACKNEXT
ENG |
4. Sets
@ Sets, like maps, come in two forms: hashed and ordered. Sets are of course just collections of values and there is no question of a key (we can perhaps think of the value as being its own key). Thus in the case of an ordered set the values are stored in order whereas in the case of a map, it is the keys that are stored in order. As well as the usual operations of inserting elements into a set and searching and so on, there are also many operations on sets as a whole that do not apply to the other containers – these are the familiar set operations such as union and intersection. @ Here is the specification of the ordered sets package giving just those facilities that are common to both kinds of sets.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Rationale for Ada 2005: 6a Containers
ENGRUSTOPBACKNEXT4. Наборы
@ Наборы также как и карты могут быть двух видов: хэш и упорядоченными. Наборы - только коллекции значений без какого бы то ни было ключа (мы можем думать о значении как о своего рода ключе самого себя). Таким образом, упорядоченный набор подобен карте где в качестве ключа используется собственное значение элемента. Вместе с обычными операциями вставки элементов в набор, поиска и так далее, есть также много операций на наборах в целом, которые не встречаются в других контейнерах - это свойственные только для наборов операции - объединение и пересечение.
@ Вот спецификация пакета упорядоченных наборов, где представлены только те средства, которые распространены у обоих видов наборов.
|
@ Единственное отличие от пакета карт (кроме идентификаторов) состоит в том, что нет никакого ключевого типа, функции "<" и "=" относятся к типу элемента (тогда как в случае карт, операция "<" относится к типу ключа). Таким образом, отношение упорядочения "<" определённое на элементах определяет эквивалентность между элементами, тогда как "=" определяет равенство.
@ Два элемента могут быть эквивалентными, но не обязательно при этом равными. Например, в случае строк мы могли бы решить, что упорядочение (и, таким образом, эквивалентность) игнорировало бы буквенный регистр, но равенство должно было бы принять во внимание этот факт. (Они могли также быть равными, но не эквивалентными, но это возможно менее вероятно). И как в случае пакета карт, операция равенства на элементах только пользуется функцией "=" для того, чтобы сравнить два набора.
@ Снова у нас есть обычные правила как и для карт. Таким образом, если X < Y является истиной тогда Y < X должно быть ложью; X < Y и Y < Z должен подразумевать X < Z; и X = Y и Y = X должно быть эквивалентно.
@ Для удобства пользователя функция Equivalent_Elements объявлена явно. Она выглядит выполняет примерно следующее:
|
@ Функция Equivalent_Elements соответствует формальному настроечному параметру с таким же именем в пакете хэш - наборов, который будет обсуждаться ниже. Это должно облегчить преобразование между двумя формами пакетов.
|
@ Отметим добавление функций Equivalent_Sets и To_Set. Два набора эквивалентны если у них один и тот же ряд элементов и пары элементов эквивалентны. Это контрастирует с функцией "=" где пары элементов должны быть равными, а не эквивалентными. Помните, что элементы могут быть эквивалентны, но при этом не обязательно должны быть равными (как в примере упомянутой выше строки). Функция To_Set берет единственный элемент и создает набор. Она особенно удобна когда используется вместе с операциями, такими как Union, описывемыми ниже. Другие подпрограммы как в других контейнерах.
|
@ Опять же они такие как и ожидается за исключением того что нет никакой процедуры Update_Element. Это потому что элементы упорядочены в терминах их собственного значения (в соответствии с установленным порядком или через хеш-функцию) и если мы только изменяем элемент на месте тогда это может стать неуместным (эта проблема не возникает с другими контейнерами). Это также означает, что Replace_Element должен гарантировать что значение New_Item не эквивалентно элементу в различной позиции; в этом случае возбуждается исключение Program_Error. Мы вернёмся к проблеме без вести пропавшей Update_Element позже.
|
@ Производит такое же действие как и в других контейнерах.
|
@ Эти процедуры вставляют новый элемент в набор, если эквивалентный элемент ещё не существует. Если он действительно существует тогда первая возвращается с параметром Inserted установленным в False и параметром Position указывающим на элемент, тогда как вторая процедура поднимает исключение Constraint_Error (значение элемента при этом не изменяется). Если эквивалентный элемент не находится в наборе, тогда он добавляется и Position устанавливается соответственно.
|
@ Это несколько походит на последнюю процедуру Insert за исключением того, что если эквивалентный элемент уже находится в наборе тогда, он заменяется (вместо того, чтобы поднять исключение Constraint_Error).
|
@ В этом случае Constraint_Error возбуждается, если эквивалентный элемент не существует.
|
@ Если элемент, эквивалентный Item уже находится в наборе, то он удаляется.
|
@ Они удаляют элемент. В первом случае, если нет такого элемента, возбуждается исключение Constraint_Error. Во втором случае, если курсор - No_Element, также имеет место Constraint_Error - есть также проверка для гарантии того что курсор определяет элемент в правильном наборе (напомним, что курсоры определяют и объект и контейнер); если эта проверка терпит неудачу, возбуждается исключение Program_Error.
@ И теперь некоторый новый материал, обычные операции набора.
|
@ Они все делают точно, что можно было бы ожидать используяь отношение эквивалентности элементов.
|
@ Они также самоочевидны.
|
@ Они должны быть самоочевидными и очень похожи на соответствующие операции карт. Снова в отличие от операций векторов и списков Find логически ищет целый набор, а не только начинающийся в некоторой точке (нет также никакого Reverse_Find). Кроме того, Find использует отношение эквивалентности основанное на параметре "<".
|
@ Они такие же что и для других контейнеров.
@ Пакеты наборов включают внутренний настраиваемый пакет по имени Generic_Keys. Этот пакет позволяет некоторым операциям набора быть выполненными в терминах ключей, где ключ - функция элемента. Обратите внимание, что в случае карты, элемент определен в терминах ключа, тогда как здесь ситуация полностью изменена. Эквивалентные отношения определены для этих ключей также; они определены настраиваемым параметром "<" для упорядоченных наборов и Equivalent_Keys для хэш - наборов.
@ В случае упорядоченного набора формальные параметры следующие:
|
@ Следующее является общим для пакета Generic_Keys как для хэш так и для упорядоченных наборов.
|
@ и в конце мы имеем:
|
@ Ожидается, что большинство пользователей наборов будет использовать их прямым способом и что операции, определенные для наборов такие как Union и Intersection будут доминирующими.
@ Однако, наборы могут использоваться как вид карт экономического класса при использовании внутреннего пакета Generic_Keys.
@ Хотя это конечно не для новичка, мы покажем пример того как это можно использовать наборы вместо карт. Мы объявляем:
|
@ Здесь мы поместили всю информацию в один тип.
@ Мы тогда объявляем "<" как обычно:
|
@ и затем иллюстрируем пакет таким образом:
|
@ Мы использовали механизм заданный по умолчанию для настраиваемого параметра "<" на сей раз посредством иллюстрации.
@ В этом случае мы добавляем элементы к памяти следующим образом:
|
@ Процедура для проверки стойки может теперь быть такой:
|
@ Хотя это и работает, но не совсем удовлетворительно. С одной стороны, мы должны были вставить фиктивные компоненты в вызове Find (используя <>), кроме того, мы должны были заменить весь элемент, хотя мы только хотели обновить Stock компонент. Кроме того, мы не можем использовать Update_Element, потому что он не определен для наборов вообще. Напомним, что это могло бы нарушить порядок элементов; но в данном случае это не было бы проблемой, потому что мы не хотим менять числовой код запчасти.
@ Лучший подход должен использовать числовой код запчасти как ключ. Мы определяем:
|
@ и тогда:
|
@ Отметим, что мы не должны определять функцию "<" для типа Part_Key вообще, потому что она уже существует, так как Part_Key - целочисленный тип. И реализация использует соответствующую функцию по умолчанию.
@ И теперь мы можем перезаписать процедуру Request следующим образом:
|
@ Это кажется тяжелой работой, но имеет ряд преимуществ. Во-первых, вызов Find является более естественным и вовлекает только числовой код запчасти (ключ) - отметим, что это вызов функции Find в реализации Generic_Keys использует только числовой код запчасти. Во-вторых, это обновление вовлекает только изменяемый компонент. Мы упоминали ранее, что нет никакого Update_Element для наборов из-за опасности создания значения, которое было бы в неправильном месте. В случае длинно названного Update_Element_Preserving_Key также выполняется проверка для гарантии того что элемент находится действительно все еще в правильном месте (проверяется что ключ - всё ещё тот же самый); если это не так, то элемент удаляется и возбуждается исключение Program_Error.
@ Если пользователь пожелает воспользоваться пакетом Generic_Keys абсолютно жизненно важно, чтобы относительная операция и функция (Part_No), используемая для иллюстрации Generic_Keys, были совместимы с упорядочением, используемым для иллюстрации родительского пакета Containers.Ordered_Sets непосредственно. Если дело обстоит не так, тогда небо могло бы обрушиться.
@ Случайно, процедура для того, чтобы проверить стойку, которая ранее использовала пакет карт теперь становится:
|
@ Здесь единственное изменение состоит в том, что вызов Key в:
|
@ заменен на Element. Небольшое отличие состоит в том, что мы можем избежать вызова Element дважды, объявляя константу E в Check_It таким образом:
|
@ и затем написав E.Stock < Low и вызывая Put_Line с E.Part_Number.
@ Более важный момент состоит в том, что если мы проиллюстрировали внутренний пакет Generic_Keys как было проиллюстрировано выше, тогда мы можем оставить Check_It неизменной, чтобы вызвать Key. Но важно понять, что тогда мы вызываем функцию Key внутренней к реализации Generic_Keys (flippantly вызываемый абонент) а не от реализации родительского пакета упорядоченных наборов (Store_Sets), потому что у этого нет такой функции. Это показывает тесную близость между пакетами наборов и пакетами карт.
@ И наконец, есть пакет хэш наборов, у которого есть сильные общие черты c пакетом упорядоченных наборов и пакетом хэш - карт. Мы можем ввести его как хэш карту, давая различия с пакетом наборов, дополнительными средствами в каждом и воздействии на примере обработки числового кода запчасти.
@ Спецификация пакета хэш - наборов начинается:
|
@ Отличие от пакета упорядоченных наборов состоит в том, что появляется дополнительный настроечный параметр Hash, а параметр упорядочения "<" заменяется функцией Equivalent_Elements.
@ Так, если мы имеем:
|
@ (которые очень похожи на пример хэш - карты, за исключением имени типа параметра), тогда мы можем иллюстрировать пакет хэш - наборов следующим образом:
|
@ и затем остальная часть нашего примера будет как и прежде. Таким образом, это легко преобразовать из упорядоченного набора в хэш - набор и наоборот, конечно, это возможно только если мы используем средства обычные для их обоих.
@ Нужно также упомянуть, что у внутреннего пакета Generic_Keys для хэш - наборов есть следующие формальные параметры:
|
@ Отличие от упорядоченных наборов состоит в добавлении функции Hash и замене оператора сравнения "<" на функцию Equivalent_Keys. (Кстати, пакет Generic_Keys для упорядоченных наборов также экспортирует функцию Equivalent_Keys для однородности с пакетом хэш - наборов). Хотя сам наш пример неизменен, мы действительно должны изменить реализацию Generic_Keys таким образом:
|
@ и тогда:
|
@ Хеш-функция подобна используемой с хэш - картами. Тип Part_Key и функция Part_No такая же что и у упорядоченных наборов. Мы действительно не должны объявлять функцию Equivalent_Parts, так как мы можем использовать "=" как фактический параметр для Equivalent_Keys.
@ Мы закончим обсуждение наборов кратко рассматривая дополнительные средства в двух пакетах наборов (и их внутренние настраиваемые пакеты ключей) так же как мы это делали для двух пакетов карт (обсуждение почти идентично).
@ У пакета упорядоченных наборов есть следующие дополнительные подпрограммы:
|
@ Они снова в значительной степени самоочевидны. Функции Floor и Ceiling такие же что и для упорядоченных карт - Floor ищет последний элемент, который не больше чем Item, а Ceiling ищет первый элемент, который не меньше чем Item - все они возвращают No_Element, если такого элемента нет.
@ Функции "<" и ">" очень важны для упорядоченных наборов. Первая эквивалентна:
|
@ Есть общая философия, что контейнерные пакеты должны работать эффективно, даже если сами элементы являются очень большими - возможно даже другими контейнерами. Мы должны поэтому избегать копирования элементов. (Передача их как параметры не является никакой проблемой, так как они передаются по ссылке, если они окажутся большими структурами). Таким образом, в этом случае, встроенное сравнение ценно, потому что оно позволяет избегать копирования, которое произошло бы, если бы мы написали функцию самостоятельно с явными внутренними запросами функции Element.
@ С другой стороны, есть общее ожидание, что ключи будут маленькими и, таким образом, нет никакой соответствующей проблемы с копированием ключей. Таким образом, такие встроенные функции менее важны для карт чем для наборов, но их предоставляют для карт для однородности.
@ Следующее дополнение в пакете Generic_Keys для упорядоченных наборов:
|
@ Это соответствует формальному настроечному параметру с токим же именем в пакете Generic_Keys для хэш - наборов упомянутых ранее.
|
@ Они эквивалентны аналогичным функциям родительского пакета за исключением того, что они используют формальный параметр "<" для Generic_Keys для поиска.
@ У хэш - наборов как и хэш - карт имеется средство для определения ёмкости как и у векторного пакета.
@ Таким образом мы имеем:
|
@ Поведение такое же как для векторов и хэш - карт. Мы не обязаны устанавливать ёмкость самостоятельно, так как она будет автоматически расширена по мере необходимости, но мы можем значительно улучшить производительность если мы установим ёмкость заранее. Обратите внимание, что Length (S) не может превысить Capacity (S).
@ Другие дополнительные подпрограммы для хэш - наборов:
|
@ Снова, они очень важны для наборов. Первая выполняет примерно следующее:
|
@ и еще раз мы видим, что встроенные функции могут избежать копирования типа Element, которое произошло бы, если бы мы написали функции самостоятельно.
2010-10-24 00:26:58
. .