- •Информационная модель предметной области
- •Моделирование задач на эвм
- •Преобразование информации при решении задачи на эвм
- •Понятие о данных
- •Абстрактные структуры данных
- •Классификация структур данных
- •14101954
- •Абстракция
- •Лекция 6. Види та методи абстракції в програмуванні. Абстракция через параметризацию
- •Абстракция через спецификацию
- •Виды абстракций
- •Лекция 7. Процедурна абстракція. Специфікація процедурної абстракції. Процедурная абстракция
- •Спецификации
- •Спецификации процедурных абстракций
- •Реализация процедур
- •Более обобщенные процедуры
- •Создание процедурных абстракций
- •Заключение
- •Лекция 8. Абстракція даних Абстракции данных
- •Спецификации для абстракций данных
- •Реализация на языке clu
- •Замечания по поводу операций up и down
- •Использование абстракций данных
- •Лекция 9. Реалізація абстракції даних. Функція абстракції. Функція інваріант подання.
- •Функция абстракции
- •Инвариант представления
- •Сохранение инварианта представления
- •Изменяемые представления
- •Параметризованные абстракции данных
- •Будем искать решение нашей задачи в виде цикла, имеющего следующий вид:
Инвариант представления
В ориентированных на работу с типами языках (как, например, в языке CLLJ) контроль типов гарантирует, что если абстрактный объект типа передается как аргумент операции типа, то этот абстрактный объект представляется объектом типа представления. Во многих случаях, однако, не все объекты представления являются законными представлениями абстрактных объектов. Например, для кластераintset(рис. 4.5)каждый массив независимо от значений является элементомЯ',например, массивы [1: 1, 7,6], [1: 1, 6, 6]и [1:6, 1,7].Однако в реализацииintsetмы решили, что каждый элемент набора записывается в массив только один раз. Следовательно, законные представления наборовintsetв этом кластере не содержат дублирующих друг друга элементов; [1: 1, 6, 6],например —незаконное представление.
Условие, которому удовлетворяют все законные объекты, называется инвариантом представления.Инвариант представления 1есть предикат
I:rep→bool
который принимает значение trueдля законных объектов представления. Например, для кластераintsetмы можем дать следующий инвариант представления:
%Инвариант представления есть
%Для всех целых i, j,таких, чтоlow (r) <=i<j<=high[j]
% r[i] ~= r[j]
Заметим, что для массива II: 1, 6, 6] 1принимает значениеfalse, а для массивов [1: 1, 7, 6]и [1: 6, 1, 7]- значениеtrue. Заметим также, что мы не включаем в 1условия, которые принимают значениеtrueдля всех массивов (например,size (r) =high(r) -low(r) + 1),потому что это гарантируется процедурами работы с массивами и соответственно предполагается в реализацииintset.
В качестве второго примера инварианта представления рассмотрим альтернативное представление наборов intset, состоящее из булева массива размерности 100и массива целых:
гер = record [els: array [bool], other.els: array tint], size: int]
Идея заключается в том, что для целых от 1до 100мы отмечаем их принадлежность набору, записывая значениеtrueвr_elsti 1.Не принадлежащие этому диапазону целые записываются вother.elsточно так же, как в нашей предыдущей реализацииintset. Так как невыгодно вычислять размер набораintset, просматривая все элементы массиваels, мы записываем этот размер в представление в явном виде. Это представление хорошо, если почти все члены набора принадлежат диапазону 1-100.(В противном случае пространство, требующееся для массиваels, будет использоваться неэффективно.) Таким образом, мы имеем
%Функция абстракции есть
% А (r) = {r_other_els [i ] | low (r. other_ els) <= i <= high (r_other_els)}
% U
% {j | 1<= j <= 100 & r.els [j])
Здесь Uобозначает математическое объединение двух наборов. Итак,
%Инвариант представления есть
% size (r.els) = 100 & low (r.els) = 1
% & все элементы r.other не принадлежат диапазону 1-100
% & в r.other нет дубликатов элементов
% & r.size = size (r.other, els) +
% (число элем. со знач. true в r.els)
Заметим, что поле sizeв этом представлении излишне: оно содержит информацию, которая может быть получена из остальной части представления путем вычислений. Но, поскольку такая излишняя информация все же содержится в представлении, взаимосвязь этой информации с остальной частью представления должна быть объяснена в инварианте представления (например, последняя строка нашего инварианта представления).
Иногда удобно использовать в инварианте представления или в функции абстракции вспомогательную функцию. Например, последняя строка инварианта представления может быть переписана следующим образом:
% r.size= size (r.other_els)+ cnt (r.els, low (r.els))
% где cnt (a, i) = if i »> high (a) then 0
% else if r [i] then 1+cnt (a, i+1)
% else cnt (a, i + 1)
Вспомогательная функция cntопределена здесь рекурсивно.
Интересный инвариант представления имеет реализация полиномов poly, представленная на рис. 4.7.Вспомним, что мы решили не записывать нулевые коэффициенты справа и слева от значащих членов полинома и представлять нулевой полином пустым массивом. Следовательно, мы предполагаем, что старший и младший элементы массива —не нули. Кроме того, эти массивы всегда имеют неотрицательную нижнюю границу. И наконец, пустой массив (представляющий пустой полином) должен иметь верхнюю границу, равную нулю. Таким образом, мы имеем
%Инвариант представления есть
%low (r) >= 0
% & if empty (т) then high (r) = 0
% else r (low (r) ]~=0 &r [high (r)] ~=0
Вспомним, что реализация операции degreeпредполагает, что верхняя граница массива равна степени полинома. Теперь мы видим это требование в инварианте представления.
Иногда все объекты представления законны. Тогда мы просто имеем
%Инвариант представления есть
%true
Инвариант представления должен быть явно задан также и в этом случае. Он освобождает осуществляющего реализацию от возможной зависимости от какого-то более сильного инварианта.
Инвариант представления —это «инвариант» потому, что он всегда сохраняется для представлений абстрактных объектов, т. е. он сохраняется, если объект используется вне его реализации. Инвариант представления не должен, однако, обязательно сохраняться всегда: он может быть нарушен при выполнении одной из операций типа. Например, операцияpoly$addможет получить массив с нулевым старшим и младшим элементом, но такие элементы удаляются из массива перед возвратом из операцииadd. Инвариант представления должен сохраняться при возврате из операций.
Между функцией абстракции и инвариантом представления имеется определенная взаимосвязь. Функция абстракции имеет смысл только для законных представлений, так как только они представляют абстрактные объекты. Следовательно, нет необходимости определять ее для незаконных представлений. Например, как мы упоминали раньше, функция абстракции для полиномов имеет некую область определения —она определена только в случае, если массив имеет неотрицательную нижнюю границу. Этому требованию удовлетворяют все законные представления полиномов, что отражено в инварианте представления.
Существует соглашение отом, что должно быть отражено в инварианте представления. Инвариант представления должен отражать все требования, от которых зависят операции, но может не отражать дополнительные требования. Например, все конкретные объекты для реализации, представленной на рис. 4.5, имеют нижнюю границу, равную, 1,но от этого не зависит реализация никаких операций, поэтому нет необходимости отражать это в инварианте представления. Хорошо представлять себе, что операции реализуют различные люди, которые не общаются друг с другом. Тогда понятно, что инвариант представления должен содержать все требования, которые необходимо знать этим различным людям.
При реализации абстракции данных инвариант представления —одна из первых вещей, о которых должен подумать программист. Он должен быть выбран до реализации операций, в противном случае различные реализации не будут согласованы друг с другом. Чтобы гарантировать согласованность, инвариант представления должен быть написан и включен в программу как комментарий. Написание инварианта представления вынуждает того, кто занимается реализацией, ясно выразить то, что он хочет, и увеличивает тем самым вероятность того, что операции будут реализованы корректно.
Все операции должны реализовываться с учетом инварианта представления. Например, предположим, что мы реализуем операцию insertтак:
insert = proc (s: cvt, x: inl)
rep$addh (s, x)
end insert
Эта реализация может создать объект с дублирующимися элементами. Если мы знаем, что инвариант представления запрещает такие объекты, то эта реализация очевидно некорректна. Инвариант представления также полезен для того, кто изучает реализацию. Например, в альтернативной реализации набора intsetмы можем решить подвергать массив представления сортировке. В этом случае мы будем иметь
%Инвариант представления есть
%Для всехi,j, таких, чтоlow(г) <=i <j<=high(r)
%r[i] <r[j]
Все операции тогда будут реализовываться иначе, чем на рис. 4.5.Инвариант представления говорит тому, кто изучает реализацию, почему операции реализованы именно так, как они реализованы.